Squashed 'third_party/protobuf/' changes from e35e248..48cb18e

48cb18e Updated change log for 3.6.1 release
9e1286b Updated version numbers to 3.6.1
e508fc0 Check the message to be encoded is the wrong type. (#4885) (#4949)
fc90fd6 Make assertEquals pass for message (#4947)
d85ffdc Merge pull request #4924 from xfxyjwf/3.6.x
8356d27 Add continuous test for ruby 2.3, 2.4 and 2.5 (#4829)
7fdebf2 Fix cpp_distcheck
6c82411 Fix php conformance test.
11e2eca protoc-artifacts: Update centos base from 6.6 to 6.9
6fc2bac Updated Docker setup to use GCC 4.8
b3e4e3a Remove js_embed binary. (#4709)
0b3b470 Fix cpp benchmark dependency on mac
ae8def6 Comment out unused command from release script.
9327dc7 Run autogen.sh in release script.
9209a41 Add protoc release script for Linux build.
4d0fbd1 Add cpp tests under release docker image.
474fd31 Update protoc build scripts.
b23429e Fix 32bit php tests
8758cc1 Fix php tests
bd1224e fix golang kokoro linux build
359889b fix python cpp kokoro build
c1e6c4d fix linux kokoro build in docker
22503a0 fix for API change in PHP 7.3 (#4898)
e529d16 Make ruby release configs consistent with protoc.
82019f9 Merge pull request #4900 from xfxyjwf/3.6.x
0e38f9e Fix bazel build of examples.
b5975c1 Add kokoro bazel configs for 3.6.x branch.
4a4a60b Merge pull request #4880 from nashimus/3.6.x
e184577 Merge pull request #4878 from acozzette/fix-msvc-initialization
1f7837a Additional support for building and deploying ppcle_64 artifacts
a9abc78 Fix initialization with Visual Studio
f7ada12 Build ruby gem on kokoro (#4819)
56d2753 Rename build_artifacts.cfg to release.cfg (#4818)
b907a03 Add files to build ruby artifact for mac on kokoro (#4814)
ad85c3b Added Kokoro protoc release build for OS X (#4770)
885be9c Work around MSVC issue with std::atomic initialization (#4777)
b0a8220 Added Kokoro Windows release build config for protoc (#4766)
ce04481 Use legacy name in php runtime (#4741)
d6353b4 Update php version to 3.6.0 (#4736)
ab8edf1 Merge pull request #4713 from acozzette/changelog
6ed0141 Merge pull request #4730 from acozzette/xcode
a3f31bf Update code to work for Xcode 10b1 (#4729)
9b77e9e Removed javanano from post_process_dist.sh
adf84b4 Updated the change log with changes for 3.6.0
7e199b9 Merge pull request #4706 from acozzette/cxx-11
39d2f70 Require C++11 and pass -std=c++11
a239ed2 Merge pull request #4702 from TeBoring/3.6.x
4f5eb10 Move methods out of class (#4697)
397ddf9 Add back GeneratedClassName to public (#4686)
d31864a Merge pull request #4696 from acozzette/csharp-fix
6c12ff5 Merge pull request #4695 from TeBoring/3.6.x
9d64d74 Removed duplicate using statement from ReflectionUtil.cs
5bf35ec Fix php memory leak test (#4692)
edaaea0 Merge pull request #4687 from acozzette/js-map-parsing-fix
d1af029 Fixed JS parsing of unspecified map keys
6f723a6 Always add -std=c++11 for mac (#4684)
4885b80 Merge pull request #4675 from TeBoring/3.6.x
dadc954 Fix array constructor in c extension for compatibility (#4667)
2774e54 PHP namespaces for nested messages and enums (#4536)
8b336f8 Implement array constructor in php c extension.
c9b404d PHP array constructors for protobuf messages (#4530)
7eba624 Add missing ruby/tests/test_ruby_package.proto
c19fcee Allows the json marshaller to be passed json marshal options (#4252)
5289ee0 Adopt ruby_package in ruby generated code. (#4627)
d8483a9 Adopt php_metadata_namespace in php code generator (#4622)
449e532 Merge pull request #4673 from acozzette/memory-leak-fix
daf039b Make sure to delete temporary maps used by FileDescriptorTables
15cde29 Merge pull request #4625 from liujisi/3.6.x
45eb28b Update version number to 3.6.0
b61dd9d Add file option php_metadata_namespace and ruby_package (#4609)
2213c1c Merge pull request #4538 from Mizux/patch-2
7377d81 Throw error if user want to access message properties (#4603)
5f7334f Avoid direct check of class name (#4601)
5f9232b use brew install instead of easy_install in OSX (#4537)
25625b9 Merge pull request #4590 from PetterS/undefined_fix
d14cacd Fix error in Clang UndefinedBehaviorSanitizer
513b35d Add VS2017 optional component dependency details to the C# readme (#4128)
4a09836 Fix python ext build on kokoro (#4527)
92898e9 Merge pull request #4586 from chronoxor/master
3474155 MinGW build failed
b0403a7 Merge pull request #4583 from chronoxor/master
f80a886 Cygwin build failed
05c2d01 Fix RepeatedField#delete_if (#4292)
0869b1a Add space between class name and concat message (#4577)
306f4e3 Merge pull request #4581 from Yeolar/3rd_rpc_raster
7d97808 [objectivec] Fix memory leak of exceptions raised by RaiseException() (#4556)
35e4430 Add third-party RPC implementation: raster - a network framework supports pbrpc by 'service' keyword.
fc922d1 Merge pull request #4568 from hectim/master
7f2c3ce Merge pull request #4550 from Mizux/master
1b219a1 Fix to allow AOT compilers to play nicely with reflection
9ba2fd3 typo
a21f225 Merge pull request #4553 from pherl/ruby
9972e16 Set ext.no_native = true for non mac platform
2bd7f51 fix duplicate mkdir in update_file_lists.sh
c3b152c CMake: Update CXX Standard management
3ad8efc Add .proto files to extract_includes.bat
8417871 Move to Xcode 9.3 which also means a High Sierra image.
b59da6d Remove the iOS Test App.
c36eeed Merge pull request #4520 from BSBandme/fix_kokoro_benchmark_build
4ca46ed Write messages to backing field in generated C# cloning code (#4440)
0dc4d75 Merge pull request #4504 from xfxyjwf/lite
a29e2bf Update Makefile.am for Java lite files.
8f35073 Fix benchmark build
9497a65 Merge pull request #4517 from rcane/feature/vc2017_build_fix
a9d9326 Merge pull request #4510 from BSBandme/fix_kokoro_benchmark_build
7d6d5f9 Fixed a Visual Studio 2017 build error. (#4488)
0921345 fix java benchmark, fix dashboard build
7d55040 Cleanup + documentation for Java Lite runtime.
320d56c Merge pull request #4478 from BSBandme/proto2_to_proto3_tools
e3af023 fix python
76d76ae fix conflicts
c703061 Add gogo benchmark
5fb73f8 Merge pull request #4415 from BSBandme/experiement
805174e Add script for run and upload the benchmark result to bq
d7d863e fix json_decode call parameters (#4381)
13e627a includes the expected class in the exception, otherwise the error is harder to track down (#3371)
451e044 Add __init__.py files to compiler and util subpackages (#4117)
3b6d027 For windows, all python version should use /MT (#4468)
dce8229 Add the files added in #4485.
ce24b8a Update Xcode settings
da3ce67 Deliberately call simple code to avoid Unity linker pruning
a72da27 Merge pull request #4475 from chenchuanyin/patch-1
e7e6c6b Merge pull request #4283 from ObsidianMinor/csharp/better-test-runners
f72ac9f Updated csharp/README.md to reflect testing changes
d3e8a54 Fix problem: cmake build failed in c++11  by clang
c931743 Merge branch (#4466)
579f81e js message support for jstype string on integers (#4332)
40d6eca Merge pull request #4467 from xfxyjwf/error
8f88a50 Improve error message when googletest is missing.
7f92711 Merge pull request #4411 from pravin-dsilva/protobuf-ppc64le
4274e6a Merge pull request #4447 from ejona86/cleaner-protoc-artifacts
c934d1d Merge pull request #4452 from xfxyjwf/doc
aab0f89 Merge pull request #4464 from thomasvl/includes3
bd941d5 Don't generate imports for the WKTs unless generating the WKTs.
e998b8f Add compile test sources for to test include order.
bca797d Trim imports for bundled generated protos.
014e76e Update instructions about getting protobuf source.
cdbfdd8 protoc-artifacts: Use ENTRYPOINT to enable devtoolset-1.1
67c1cd4 protoc-artifacts: Avoid storing temporary files and use fewer layers
5f052ae protoc-artifacts: Avoid checking out protobuf code
7bf47a6 Merge pull request #4433 from xfxyjwf/license
c8ed695 Merge pull request #4445 from xfxyjwf/badge
eac0e92 Add kokoro build status badges.
59c4328 Merge pull request #4442 from xfxyjwf/clean
107cd70 Delete unused directories.
d3d7cdb Merge pull request #4439 from acozzette/remove-atomicops-stub
612b670 Updated .gitignore to exclude downloaded gmock/ directory
4875dfe Removed atomicops.h since it is no longer used
2537bea Merge pull request #3794 from jskeet/reflection
9c05c35 Address review comments
7b19d20 Add extra C# file to Makefile.am
8e23d4e Work around an "old runtime" issue with reflection
aa59eaa Introduce a compatiblity shim to support .NET 3.5 delegate creation
8ba420f Change C# reflection to avoid using expression trees
63bba9b Merge pull request #4432 from xfxyjwf/rmnanokokoro
5050269 Merge pull request #4434 from xfxyjwf/buildstatus
9f5bded Remove broken build status icons.
9e080f7 Cleanup LICENSE file.
68de0cf Delete javanano kokoro build configs.
3c5442a Include googletest as a submodule (#3993)
1156ee7 source code info for interpreted options; fix source code info for extension range options (#4342)
d34e319 Merge pull request #4431 from xfxyjwf/rmnano
379b7ff Fixes MSVC compiler warning C4800 "Forcing value to bool 'true' or 'false'" (#4350)
ac67376 Merge pull request #4395 from stone4774/fixbug_enum2json2
d5a0024 Remove javanano.
416d418 Merge pull request #4424 from egorpugin/patch-1
dc68d98 Fix missing LIBPROTOC_EXPORT.
2c963d3 Merge pull request #4413 from pmuetschard/msvc
eff52b1 Merge pull request #4422 from acozzette/ruby-conformance
cf7af01 Merge pull request #4421 from acozzette/fix-bazel-build
f91cf05 Updated Ruby conformance test failure list
5bed368 Added missing .inc files to BUILD
a7a746f Merge pull request #4346 from BSBandme/performance_result
745ef89 Add performance.md and add instruction for linking tcmalloc
227363b Merge pull request #4412 from acozzette/remove-old-files
a6957f2 Don't assume Windows builds use MSVC.
0c5fcde Removed some unused C++ source files
36ba04b Add support for power ppc64le
c99f527 Merge branch 'master' into fixbug_enum2json2
d053271 Use the first enum value instead of 0 in DefaultValueObjectWriter::FindEnumDefault
ed4321d Merge pull request #4387 from acozzette/down-integrate
e436ee0 Merge pull request #4361 from BSBandme/go_benchmark
88a4884 Merge pull request #4345 from jskeet/list-json-null
11d26ce Removed unused variables in repeated_scalar_container.cc
fcde518 Try using a new version of Visual Studio on AppVeyor
8b3a72f Removed unused code pertaining to shared_ptr
ec40953 Updated conformance failure lists
ec57f51 Added map_lite_test.proto to fix LiteTest
c5fcce5 Added pyext/thread_unsafe_shared_ptr.h
3fa5dad Removed unrecognized option from no_package.proto
00b1c14 Added new test source files to Makefile.am
616fe05 Removed use of some type traits
d6323c8 Change to deal all messages in one loop
d6a17aa Merge pull request #4397 from pherl/catlog
4880027 Cat the test-suite.log on errors for presubits
773d8c3 Fix bug: whether always_print_enums_as_ints is true or false, it always print the default value of enums as strings
ab95b1b Merge pull request #4371 from Rasrack/gnuc_minor
aae10ed Merge pull request #4370 from felixjendrusch/objc-output-stream-write-check
813848d Merge pull request #4222 from JohnHBrock/increasing_max_csharp_message_size
d5f5725 Merge pull request #4310 from KindDragon/patch-1
837c94b Include no_package.proto in Python test
67952fa Deleted scoped_ptr.h
b1216d9 Updated checked-in generated code
64a5c80 Fixed up proto3_lite_unittest.cc
501c13f Rewrite go_benchmark
afe96b6 Merge branch 'master' into down-integrate
0400cca Integrated internal changes from Google
89b5333 Merge pull request #4378 from acozzette/node-buffer
4f11025 Merge pull request #4167 from mike9005/patch-1
6d2c6a0 some fix
5487d8c Merge pull request #4380 from mateuszmatejczyk/patch-1
4787519 Merge pull request #1333 from cgull/pkg-config-issue
294b575 Output *_pb2_grpc.py when use_grpc_plugin=True
0e34c86 Fix spelling error of __GNUC_MINOR__
f8005a5 Revert "Removed mention of Buffer in byteSourceToUint8Array"
8e44a86 Merge pull request #4347 from xfxyjwf/pluginpb
6ebfa14 Merge pull request #4375 from jo2y/protoc-default
950f5e4 Replace //:protoc and similar default macro arguments with @com_google_protobuf prefixed versions. This allows them to work in 3rd party repositories.
6dd563a Sync upb change (#4373)
1da9ffe Check return value on write of raw pointer
38508e9 Add test for failing write of raw pointer to output stream
4e3c413 Add go benchmark
a48d58d Convert descriptortype to type for upb_msgval_sizeof (#4357)
0f4ad85 For encoding upb needs descriptor type instead of type. (#4354)
55d0758 Merge pull request #4355 from acozzette/typo
5004d09 PHP: fixed typo in message.c
fd595fc Revert "Move `compiler/plugin.pb.cc` to libprotobuf with the other WKT sources."
5140bae Add conformance test for null value in list JSON
822b924 Allow list values to be null when parsing
9dc0a4d Merge pull request #4183 from pcc/win-libcxx
325ecff Merge pull request #4333 from jmillikin/update-file-lists-needs-bash
32db4d3 Merge pull request #4334 from jmillikin/blacklist-internal-proto-srcs
3aaed96 Merge pull request #4195 from alexey-malov/IgnoreUnknownEnumsInJson
bb40c0c Merge pull request #4291 from google/3.5.x
350b135 Blacklist all WELL_KNOWN_PROTOS from Bazel C++ code generation.
724f0be Move `compiler/plugin.pb.cc` to libprotobuf with the other WKT sources.
2e4c52a `update_file_lists.sh` depends on Bash features, thus needs Bash sebang.
a6037c5 Merge pull request #4324 from abdul-sami/master
ac021a0 Merge pull request #1 from abdul-sami/abdul-sami-patch-1
fe33c5f Added instruction for existing ZLIB configuration
177108a Merge pull request #4323 from dtapuska/master
af3813c Rename a shadowed variable.
0475607 Merge pull request #3186 from gkelly/remove-unused-variable
22c477d Support using MSVC intrinsics in Log2FloorNonZero
02452db The JsonParseOptions::ignore_unknown_fields option behavior treats unrecognized string values in enum fields as default ones.
e34ec60 Only check filenames when end with .py in _CalledFromGeneratedFile() (#4262)
96b535c Merge pull request #4302 from BSBandme/down_integ_benchmark
6cd4ec4 Sync internal benchmark changes
4da7706 Remove stray indent on normal imports.
b8e4783 Merge pull request #4288 from nico/nofall
07f0231 Fix up the docs to mention the WKTs generated files also.
c66dd6c Remove use of GOOGLE_FALLTHROUGH_INTENDED from protobuf.
8b2ba9e Remove Google.Protobuf.Test/Program.cs from Makefile.am
a731ecb Adjusted appveyor batch
e823897 Updated NUnit packages, removed NUnitLite added packages for dotnet and Visual Studio, changed dotnet command in buildall to dotnet test, and deleted Program.cs (because it's no longer required).
82e0231 Merge pull request #4259 from Mizux/master
5dad7cc Merge pull request #4257 from davido/support_java9
9717d6f Merge pull request #4265 from BSBandme/upgrade_benchmark_submodule
1ec9beb Use NEW behaviour for project VERSION variables.
8dd0f4e Even with MSVC enable zlib support as default behaviour.
f7a0584 Add CMake ALIAS targets
3bc0282 Add VERSION property to CMake library targets
7f14915 upgrade submodule
4e2bd9e Merge pull request #4266 from brunokim/patch-1
0d397a1 Fix link markup in third party list.
6456e5d Merge pull request #4239 from mrpi/master
85b488f Bazel: Support building with Java 9
864df89 Remove 64MB memory limit when deserializing messages in C#
cf016a4 Work around strange error with atomic and swift under Xcode 8.3.3.
d570d48 Don't assume c-strings are 4 byte aligned.
d83837d Fix to use "nil" instead of "NULL" for objc objects.
81aeed0 Work around the static analyzer false report.
953adb1 Add casts to removed undefined behaviors around shifts.
b718551 Merge pull request #4249 from nlochschmidt/patch-1
204a641 Move kokoro macOS builds to to Xcode 9.1.
14e8852 Fix -fpermissive: '<::' cannot begin a template-argument list
69b1fdc Propose kotlinx.serialization as 3rd party lib
25a90e8 Merge pull request #3825 from ras0219-msft/patch-1
aaf41c6 Add Vcpkg to C++ installation instructions for Windows
1681fe6 Merge pull request #4196 from mathstuf/cmake-private-target-sources
f438ebd Merge pull request #4240 from davido/generate_warning_free_java_code
da6b07a Merge pull request #4209 from acozzette/using-statements
86fdad0 Java: Generate warning free code
39a789e Removed using statements from common.h
91317c2 Merge pull request #4236 from pherl/3.5.x
2a8e102 Bumping number to fix ruby 2.1 on mac
c236896 Merge pull request #4229 from leighmcculloch/patch-1
4a3b42e Remove broken link to code.google.com/p/protorpc
ed14fe4 Merge pull request #3934 from xfxyjwf/builtsources
0c52335 Update .NET SDK to 2.0.3
51293f3 Fix more memory leak for php c extension (#4211)
94f3be0 Merge pull request #4226 from themattchan/patch-1
3e1587f Add an explicit import of stdatomic.h.
6fd2ae7 Bring back import of OSAtomic.
72337d6 Add Haskell implementations
1d02e45 Merge pull request #4224 from davido/drop_java_6_support
019ceea Drop java 6 support
c337d9f Remove the use of BUILT_SOURCES
9ab859f Create std::string in Arena memory
80e016e Merge pull request #4205 from xuwei-k/patch-2
a721bf6 Migrate away from deprecated OSAtomic APIs. (#4184)
1c3b20b fix typo in FieldMaskTree.java comment
9d0a44c cmake: privately add sources to targets
cbdeb6a Merge pull request #4185 from pherl/ruby2.5
53d907f Update rake file to build of 2.1.6.
3ba21cd Add support for libc++ on Windows.
979c2cd Merge pull request #4182 from pherl/ruby2.5
d9f0f0b Support ruby2.5
47b7d2c Add DiscardUnknownFields support for C#
2a6eaeb Fix scope resolution for MessageExts in Ruby
9f80df0 Merge pull request #4158 from BSBandme/FixBenchmarks
473a810 Update py_benchmark.py
fa60e55 Fix java benchmark to use parser, fix cpp benchmark new arena to use Reset, format some files
b77aa80 Merge pull request #4148 from datacompboy/patch-2
d4afdba Merge pull request #4147 from datacompboy/patch-1
bab843b Merge pull request #4132 from BSBandme/JavaCaliperCounter
195253c Add counter to Java benchmark
4adc5a4 Merge pull request #4065 from BSBandme/python_benchmark_real
091eeb1 Update time_test.cc
473c5cf Fix ValidateDateTime: check day instead month
3823897 Well known types are not initialized properly. (#4139)
2fc69b1 Add python benchmark
5aa8f98 Merge pull request #4146 from pherl/fix_protoc
366192f Bump protoc-artifact version for a patch rebuild
a3868af Merge pull request #4131 from pherl/merge
eca1d2a Merge pull request #4116 from amandeepgautam/master
0c0d481 whitelisting aix platform as it has sched_yield
4588e6e Force a copy when saving the NSData that came from another.
43caa38 Merge pull request #4014 from BSBandme/JavaCaliper
ec826c5 Merge remote-tracking branch 'origin/3.5.x' into master
383a494 Merge remote-tracking branch 'origin/3.5.x' into master
39f577c Merge pull request #4124 from pherl/nullptr
5b1caea Merge pull request #4090 from pherl/nopassword
156161d Properly copy maps with string keys but pod values.
aca6c15 Fix some bug
4f3d865 remove nullptr
a147a21 Changed README
8529f2a Resolved issue #3510. Malformed errorr messages replaced with meaningful description
8fc40b5 Fix uploading binary wheel.
88e5573 Merge pull request #4089 from pherl/nocache
7ad8e7a Disable pip cache when testing uploaded packages
099d997 Merge pull request #4083 from matt-kwong/kokoro_jobs
0b2be3c Shard 64-bit Linux languages into different Kokoro jobs
4b2977b Merge pull request #4082 from matt-kwong/kokoro_jobs
ae49cfd Collect xml results for Kokoro
106ffc0 Merge pull request #4073 from pherl/changelog
d69f333 Merge pull request #4080 from pherl/arm64
6003a61 Make Kokoro job pull Dockerimage from Dockerhub
ad8a82e Add support for Windows ARM64 build
b5f09c1 Merge pull request #4077 from mkamilov/master
a5b743f Merge pull request #4030 from cyyber/master
7bf1e19 Update changelog
1e418e4 Merge pull request #4068 from wsw2016/fix_4032
ac1fdd1 line breaks adjsted
e68caa3 formatting issues
d106399 Merge pull request #4072 from google/jieluo
6c3c7f6 Merge pull request #4076 from pherl/stringback
b308580 Cherrypick for csharp, including: Add preserve UnknownFields Compare floating point values bitwise Add auto-generated header to C# generated files
19d0e99 Fix string::back() usage in googletest.cc
62616e1 Update changelog
96810de Merge branch '3.5.x' of github.com:google/protobuf into changelog
eff55ec Merge pull request #4074 from pherl/mapat
8ac050f Migrate Jenkins jobs to Kokoro
9ce29bd Merge pull request #4070 from pherl/3.5.x
501093d Replace C++11 only method std::map::at
7bd1606 Update changelog for 3.5.1
050fc9a Update version number to 3.5.1
ffa18ad resolve issue 4032 and added a unit test
03fb099 Add support for Windows ARM64 build
860d693 Add Xcode 9.2 to the testing support
3a06fe1 Fix file permission for python package.
77d32bc Merge pull request #4053 from xfxyjwf/fixumask
c79ba5c Merge pull request #4034 from TeBoring/php-timestamp-bug
269884a Merge pull request #4040 from bazurbat/3.5.x
0fc85ac Fix file permission for python package.
4b02091 add cpp
396336e Merge pull request #4046 from acozzette/deprecated-valueof-issue-2054
8d6f13e Fix for php5.5
1237c3f Merge pull request #4045 from pherl/deprecate
d971cbf Merge pull request #4049 from pherl/py26
39159c8 Accept DatetimeInterface in fromDatetime
0e2089c Calling Keychecker before checking key in MessageMap
acadade Remove py2.6 support.
594ec22 Fix python descriptor test.
cd32aae Merge branch 'master' of https://github.com/google/protobuf into JavaCaliper
75523ec fix bugs
1a549d9 Avoid using php_date_get_date_ce() in case date extension is not available.
0350111 Generate an annotation to suppress deprecation warnings
426cf6f Add auto-generated header to C# generated files (#4038)
34843ed Fix bugs
a4f68d4 Merge pull request #4044 from xfxyjwf/issue3268
00ac5c1 Merge pull request #4041 from acozzette/fix-license-issue-1775
22e1cfd Add deprecation annotation for oneof case.
b3ac441 Update generated code.
bfd254e  Add unknown field support for csharp (#3936)
50ef6a6 Avoid two consecutive underscores in macro name.
82724e2 Merge pull request #4042 from pherl/cpp_enum
8521624 Merge pull request #4043 from pherl/flush
0a7120a Merge pull request #4037 from xfxyjwf/issue2880
6b01e64 Explicitly propagate the status of Flush().
7ef21dd Use matching enum type for IsPOD.
ecab9c6 Added our standard license header to structurally_valid.cc and its test
edcf15e Create containing directory before generating well_known_types_embed.cc
5ce724b Merge pull request #4036 from xfxyjwf/issue3093
fffe8d3 Call php method via function name instead of calling directly.
0f9bfa8 Merge pull request #4016 from jquesnelle/string-access-ub
27e877f Merge pull request #2834 from aj-michael/master
6c27550 Clarify default value behavior in JSON conversion.
75eceb8 Update generated code.
8489612 Update comments for Timestamp JSON format.
f69a5db Merge pull request #4028 from TeBoring/3.5.x
88102ea Replace private timelib_update_ts with public date_timestamp_get
9f6acea Add PROTOBUF_ENABLE_TIMESTAMP to let user decide whether timestamp util can be used at install time.
5e732e3 Add caliper supported to java benchmark
b1386e7 Merge pull request #4026 from TeBoring/3.5.x
3b13c3f Add backslach to make class explict in global namespace
fc5818b Merge branch '3.5.0.1' into 3.5.x
31c54d1 Regenerated code from previous C# codegen commit
3e5bd2f C# code generation changes to use bitwise comparisons for doubles
f3e9a65 Compare floating point values bitwise in C#
618f06f Merge pull request #4007 from graywolf/patch-1
a426833 Merge pull request #4000 from Kwizatz/master
cf7c15e Fix ruby gc_test in ruby 2.4 (#4011)
9b09a2a Merge pull request #4017 from acozzette/update-file-lists
0fcca8f Merge pull request #4018 from acozzette/android-portable-log2-floor
f5b0862 use const char* instead of const std::string& in normalize()
63a0afc Use the portable version of Log2Floor for Clang with older Android NDK versions
0e7b589 Add discard unknown API in ruby. (#3990)
609d752 Ran update_file_lists.sh to update Bazel and CMake file lists
b32c2a8 fix undefined behavior in C++03
24493ee Using binary one's complement to negate an unsigned int
c370f88 Recursively clear unknown fields in submessages. (#3982)
1b5b3b2 Merge pull request #4013 from laszlocsomor/io_win32
a3a1c93 io_win32_unittest: remove incorrect error check
eb3bd6e io_win32_unittest: fix condition in GetCwdAsUtf8
3f1b1a6 io_win32_unittest: use CWD as last tempdir
57a01c7 io_win32: add more encoding-related tests
65da9fd io_win32: support non-ASCII paths
953a025 io_win32_unittest: make //:win32_test run again
457f6a6 Add release log
ba60b85 Update php c extension version number to 3.5.0.1
212563d Fix memory leak in php7
3b7a5f4 Fix several more memory leak
7d34371 Fix memory leak when creating map field via array.
e0d3aa0 Fix memory leak when creating repeated field via array.
de44982 Remove duplicate typedef. (#3975)
0316ae8 --pre is not necessary
9021f62 Merge pull request #3988 from acozzette/down-integrate
173f304 Merge pull request #3926 from BSBandme/down_sync_benchmark
e372df5 Fixed failing JS tests
db7c043 Merge pull request #3968 from fahhem/patch-2
35119e3 Add a check_protobuf_required_bazel_version() for use in WORKSPACEs
1fd6c17 Fix bugs to pass tests
7bb8584 Updated conformance failure lists
b140cb3 Fix memory leak when creating map field via array.
716acc3 Remove Xcode directives on some configs.
1acacf4 Fix memory leak when creating repeated field via array.
1c062a6 Sync internal benchmark changes
5d647e1 Updated Makefile.am to add a new file to EXTRA_DIST
0ba8eea Merge branch 'master' into down-integrate
92a7e77 Integrated internal changes from Google
a711e3d Merge pull request #3979 from acozzette/3.5.x-merge
a27da09 Merge branch '3.5.x' into 3.5.x-merge
94bb1ee Remove duplicate typedef. (#3975)
74e7dec Provide discardUnknonwnFields API in php (#3976)
6de51ca Merge pull request #3824 from anuraaga/dev_rag
da89eb2 Merge pull request #3955 from linux-on-ibm-z/master
6d60995 Update csharp version number (#3958)
0289dd8 Merge pull request #2519 from rubynerd-forks/ruby-fix-repeated-message-type-field
74f64b6 Fix JsonTokenizer exception message
3e944ae Add a UTF-8 decoder that uses Unsafe to directly decode a byte buffer.
3c6fd3f Merge pull request #3960 from acozzette/libprotoc-export-fix
1b1d1ea Added back in LIBPROTOC_EXPORT which was removed by mistake
34e30e5 Merge pull request #3962 from jleni/fix_dotnet
582d6ac Upgrading dotnet to 1.0.4
f2127b6 Merge pull request #3416 from xiaoshuang-lu/PROTOBUF-3404
642e1ac Adding Release_CompareAndSwap 64-bit variant
8ff2284 [PROTOBUF-3404] add --with-zlib=PATH to configure.ac script
cf65a79 Update version for 3.5.0.post1
f466709 Merge pull request #3941 from google/anandolee-patch-2
45d99a1 Add _file_desc_by_toplevel_extension back
f08e4dd Merge pull request #3919 from jart/less-warnings
b819abf Merge pull request #3918 from OEP/fix-sdist
ac5371d Remove unhelpful build warnings
9935829 Include .cc and .h files in source distribution
baed06e Small code reorder to maybe make #3893 happy.
6700f41 Travis config cleanups and move ObjC to Xcode 9.1.
2b3aa1c Add Setter/Getter type verification. (#3880)
8537f1e Fix up warnings from Xcode 9.1 (#3887)
98836a5 Update version number for php c extension (#3896)
e99e5d0 Merge pull request #3895 from pherl/3.5.x
1ec45f8 Add protobuf-all in post release
857a021 Use fully qualifed name for DescriptorPool in Any.php to avoid name (#3886)
0d46688 Update README.md: C extension works on PHP 7 (#3888)
696653d Merge pull request #3892 from sergiocampama/32bit
7daa320 Merge pull request #3878 from Yangqing/master
02129f0 Fixes 32bit tests.
cf68531 Merge pull request #3891 from thomasvl/travis_cleanups
7417755 Merge pull request #3883 from dmaclach/map_optimizations
8ae6844 codereview cleanup
6552c5a Merge pull request #3884 from dmaclach/unsafe
4ba3092 code review cleanup
af5ad24 Merge pull request #3882 from dmaclach/removeclass2
a839c67 Remove the allowed_failure for python_cpp as the bug was fixed.
2e17639 Remove the ruby tests from travis configs.
c46571b Update some comments about testing.
73e8c8a Instead of listing and then excluding osx builds, just don't list them.
949596e Simplify getter/setter method implementations
9d7f313 Reduce size of GPBDictionary by getting rid of class creation methods
37a6672 Remove unreferenced 'GPBMessageSignatureProtocol' class.
91ff83c Remove non-C# options from C#-only test protos
cba18ef Allow one to omit building libprotoc and protoc binaries
d3537c2 Merge pull request #3834 from sviterok/patch-1
0cd2ad1 Update protoc-artfacts
2720cdc Update README.md
4041600 Merge branch '3.5.x' of github.com:google/protobuf into 3.5.x
4493595 Update release date
2761122 Merge pull request #3868 from pherl/3.5.x
b9f891e Merge pull request #3875 from hchasestevens/add-hypothesis-protobuf-doc
188f180 All integer types should accept null in json. (#3869)
3c33143 Add hypothesis-protobuf library to the 3rd party doc.
8cf53f8 MMinor fix-ups to C# tests from changes in earlier commits
b5cdf0e Regenerated test code for C#
aa77eab Move C#-only test protos to csharp/protos
9a9a66e Run C# codegen when testing it
9c197b7 Support win32 long path for cross compiled build
fe2b4af Merge pull request #3867 from jtattermusch/update_changelog
07df230 update changelog
966a9ed Merge pull request #3861 from jtattermusch/backport_3858
5f96191 ParseFrom<T> for array slice is missing
4a5e1bd check already performed by MergeFrom
435f611 allow message parsing from an array slice
ce0a532 Merge pull request #3858 from jtattermusch/parsing_from_slice
5eb717c Fix arm64 name
b879abc Supports Arm64 (aarch64) protoc artifacts
30b6e54 ParseFrom<T> for array slice is missing
07542e7 check already performed by MergeFrom
0c874a6 allow message parsing from an array slice
0971efb Merge pull request #3854 from pherl/3.5.x
662e8b2 Provide util funtions to figure out correct php class names. (#3850)
181e284 Fix Atomic32/AtomicWord on some platforms.
1144768 Merge pull request #3835 from pherl/3.5.x
8a3c5cc Fix java code example
ce2d528 Changelog for 3.5.0
c258fb3 Merge pull request #3822 from mehrdada/update-benchmark-submodule
2df4726 Fix php well known type conformance tests (#3828) (#3840)
bcda919 Fix php well known type conformance tests (#3828)
239dba5 Merge pull request #3839 from thomasvl/message_equality
1f57e54 When comparing message, require them to have the same descriptor.
1908012 Update generated descritpors.
97dd175 Update version number to 3.5.0
da3bfa6 Fix a typo in WKT's test suite
cbe2505 Fix merging with message-valued oneof
bb35f04 Update google/benchmark submodule to v1.2
6dd8224 Merge pull request #3817 from xuwei-k/joda-url
05b56d0 update joda-time javadoc url
e8c9ae1 Add parser settings WithXyz methods
a985451 Add JsonParser setting to ignore unknown field values
4526d8b Merge pull request #3722 from timou/cmake-windows-clean
23adfeb Reserve unknown in Ruby (#3763)
a08b03d Add missing files
9aaa8e1 Merge pull request #3804 from pherl/merge
2fc7aea Merge pull request #3791 from signalwerk/patch-1
cdc0d95 Merge remote-tracking branch 'origin/3.4.x' into master
ee8a091 Merge pull request #3787 from sergiocampama/coverage
b1f954e Improves coverage of GPBCodedInputStream
44daa59 To be clear that we set a new variable
a23669c Sort MSVC warning suppressions
cefa9d7 Merge pull request #3758 from spinorx/3.4.x
b189389 Merge pull request #3757 from spinorx/master
09e0dbc Merge pull request #3743 from Schtolc/master
2a14214 Merge pull request #3754 from toanju/gcc-fallthrough
07b9238 Merge pull request #3770 from pherl/3.5-integrate
2ee294d Fix Java 1.6 compile
9c407a1 Merge pull request #3751 from uykusuz/master
ca6187d Merge pull request #3578 from pherl/filedeprecation
dedf904 Merge pull request #3764 from zearen/patch-1
37f984f Merge pull request #3698 from hesmar/hesmar/fixProtocIncludeDirs
3d6cc0e Merge pull request #3641 from drivehappy/3.4.x_clang_cleanup_3
2e2614e Merge pull request #3706 from johanbrandhorst/patch-1
188755c Fix JS conformance tests
1c682e0 Fix bazel build
ecf2957 Update descriptor protos
30bfe36 Merge pull request #3736 from jleni/fix_rbpi
6b5912b Merge branch 'master' of github.com:google/protobuf
1a7a7fc Merge from google internal
dc9190f Merge pull request #3769 from pherl/io_win32
cc58be6 Fix unsiged underflow
7dbee32 Remove C++11 only usages in io_win32 tests.
c4f59dc Merge pull request #3760 from jmillikin-stripe/descriptor-memset-ub
aff1097 Fix undefined memory management found by Clang's sanitizers.
3130ce0 Fix iOS cc_library build for protobuf.
16792c6 Fix iOS cc_library build for protobuf.
37e112f fix implicit fallthrough in gcc 7
be13314 fixes issue #3750
f850188 Merge pull request #3744 from fmarier/json-escaping-namespace
5992e24 Move namespace closing brace inside the header guard block
a632f0d Merge pull request #3739 from pherl/merge3.4
1e58006 test for field reassignment
38fd94e CodedInputStream::SetTotalBytesLimit description fix
dd980cc Fix distcheck
de15e73 Merge remote-tracking branch 'origin/3.4.x' into master
08334f0 Converting to immutable hashable types
c4083bb Merge pull request #3735 from sgreenstein/patch-1
68ee916 Don't pass -lpthread and -lm on Windows
6032746 Reserve unknown fields in php (#3659)
d2a5f8b Update third_party.md
2a72840 Suppress VS2017 compiler/linker warnings
77f64bb Add well known types to php runtime. (#3697)
cd5f49d Fix ruby segment fault (#3708)
d6c32a8 Merge pull request #3714 from thomasvl/objc_increase_test_coverage
a274c67 Build out more complete code coverage in the tests.
9477123 Let Xcode 9 update project/scheme settings.
4207066 Merge pull request #3710 from thomasvl/xcode9
c4dce01 Merge pull request #3709 from thomasvl/unknown_field_merge_issue
b586e64 Add Xcode 9 support to the helper script.
3f2dcae ObjC: Fix merging of length delimited unknown fields.
210be26 Use constexpr more with VC++ 2017 (#3707)
fc7a6a2 Add GopherJS protobuf and gRPC links
bd798df Merge pull request #3690 from pherl/3.4.x
a38f876 Merge pull request #3691 from pherl/stringback
f7e2099 protobuf_generate: create include path only for proto files
d2738c0 Add spaces
5a501c6 Fix C++11 string accessors
6d0cf1b Remove ranged based for in io_win32.cc
fc5aa5d Merge pull request #3676 from hesmar/hesmar/fixProtobufGeneratePython
0e069e5 generate python code when calling PROTOBUF_GENERATE_PYTHON
ae55fd2 Enforce all error report for php tests. (#3670)
c204402 Merge pull request #3675 from hesmar/hesmar/cmakeAddDllExport
9829b8f protobuf_generate: add EXPORT_MACRO option
c627530 Merge pull request #3674 from pherl/shutdown
4fc7529 Merge pull request #3627 from zanker/zanker/add-submsg-hash-init
b091bfb Test Shutdown can be called multiple times.
633ef8b Update message.c
2b0ee3f Add $ before url_prefix_len to make it a variable. (#3668)
eade82c Merge pull request #3639 from zanker/zanker/fix-embedded-to_h
8eae3fe Update message.c
8771483 Allow initializing a chain of protos using only a hash
83264bd Fixed to_h with repeated messages to return hashes in Ruby
cf1b29d Merge pull request #2377 from mcos/chore/conformance-null-tests
fa5a69e Merge pull request #3624 from acozzette/down-integrate
655cc83 Merge pull request #3651 from pherl/3.4.x
2eb1bac Bumping minor version for ruby gems
5dd818c Merge pull request #3612 from TeBoring/php-bug
b04e5cb Merge pull request #3642 from pherl/3.4.x
dba647a Bump version for minor release
e3be1fe Clang warning cleanup for unused parameter.
13fd045 Integrated internal changes from Google
d1bc27c Merge pull request #3626 from xfxyjwf/fixgo
8136ccb Fix go example test.
c0d88ae Merge pull request #3635 from drivehappy/clang_cleanup
7f3ded6 Clang warning cleanup for unused parameter.
471b45e Merge pull request #3158 from yeswalrus/fix-policy-warning
3d78561 Merge pull request #3634 from TeBoring/ruby-bug
a459b22 Storing the frame on the map means we don't need the array
c1dd8e8 Move parse frame array to the Map object
8741da3 Revert "Fix js conformance tests. (#3604)" (#3633)
a425dd9 Rename ClassNamePrefix to ConstantNamePrefix
2bd55a9 Fix js conformance tests. (#3604)
f46a01d Exclude valid constant name from reserved name.
06aa8dc Merge pull request #3621 from jtattermusch/upport_3596
ed0a07e Merge pull request #3618 from hesmar/fix_protobuf_generate
5de0565 Google.Protobuf should target net45
444aecd fix protobuf_generate function
b1befb0 Merge pull request #3613 from xfxyjwf/bazel_examples
6945203 Exclude addressbook.proto from C# boostrap test.
ddb9ef9 Change array to map for reserved names in c extension
49b31dc Update C# generated file for addressbook.proto
49b88af Update examples file list.
89069de Change array to associate array.
174c82d Add well-known timestamps to JSON for PHP (#3564)
74bf45f Add bazel support for examples.
e5d000c Add prefix to php reserved keywords.
2ad5c0a Merge pull request #2576 from cristicbz/py-strutil
6a4ffb2 Merge pull request #3596 from jtattermusch/csharp_target_net45
054054c Merge pull request #3590 from NanXiao/patch-1
7f8b91f Add native php support for Duration. (#3583)
35b852f Merge pull request #3594 from buchgr/well-known-protos
699c0eb bazel: Add proto_library rules for well known types. Fixes #2763
50a6475 Google.Protobuf should target net45
f4ff17b Update autogen.sh
6699f2c Merge pull request #3560 from tenderlove/thread-safe-map
f9b8169 Add TODO
dd69d5c Fix dist check
baae7ea Add @Deprecated annotation support for proto file.
b70e0fd Add php support for Timestamp. (#3575)
2807436 change the field number of php_generic_service to fix the conflict with (#3576)
f55c6ec Storing the frame on the map means we don't need the array
d6152dd Move parse frame array to the Map object
c7457ef Add any support in php runtime. (#3486)
21b2372 Merge pull request #3565 from pherl/fixdist
d8c6193 Add mising cmake files in dist
98a3734 Merge pull request #3503 from gburgessiv/master
859d94a Merge pull request #3544 from anandolee/master
92ea0d2 Merge pull request #3556 from matt-kwong/kokoro_mac_v3
78432ea Remove pre-installed softwares
07de70e Merge pull request #3555 from pherl/fixdist
364060b Merge pull request #3547 from matt-kwong/kokoro_mac_build
55fdbe5 Make distcheck aware of test proto files.
e46caba Remove pre-installed softwares
c44c3af Merge pull request #3548 from google/3.4.x
30681c7 Merge pull request #3546 from pherl/deathtest
610e433 Drop python2.6
028d6f1 Add Python 3.5 3.6
6609e52 Disable death tests on windows
e416f5d Merge pull request #3537 from TeBoring/php-bug
7273b3c Merge pull request #3539 from drivehappy/3.4.x_clang_cleanup_1
09fd125 Merge pull request #3540 from drivehappy/3.4.x_clang_cleanup_2
7a43137 Merge pull request #3543 from tony612/patch-1
6cecd20 Work around a bug in clang's static analyzer
2fb7479 Add Elixir protobuf and gRPC to 3rd party doc
c27b56c Merge pull request #3494 from drivehappy/clang_warning_macro
36ac06f Merge pull request #3535 from drivehappy/clang_warn_cleanup
0b7e978 Merge pull request #3535 from drivehappy/clang_warn_cleanup
92d768c Merge pull request #3536 from pherl/io32_11
77a453a Fix compile errors
dd51909 Use message name as defined in php runtime.
4aadcd3 Remove C++11 features in io_win32.cc
ba4e547 Merge pull request #3529 from pherl/merge3.4.x
472f700 remove the parens from the cmp() lambda definition (#3526)
1183f48 Fixing unused parameter warnings under Clang.
139775c Merge remote-tracking branch 'origin/3.4.x' into mergemaster
26ac3e8 Merge pull request #3528 from pherl/rubyfix
fdb5cd5 Merge pull request #3504 from pherl/3.4.x
d76e4c7 Bump gemspec again
1825d6d Merge pull request #3317 from ejona86/protoc-artifacts-jdk8
c2aa26e Revert "Drop Python 3.3 from testing & add Python 3.5, 3.6 (#3512)" (#3524)
703f414 Drop Python 3.3 from testing & add Python 3.5, 3.6 (#3512)
a04eb8c Define cmp() for Python 3 (#3517)
1aa2c34 Merge pull request #3516 from cclauss/patch-3
dded80f define long() for Python 3
6f4c9b0 print() function for Python 3
a1acf25 print() function and lose the semicolons (;)
067543c from __future__ import print_function
7daedbd print() function & define raw_input() for Python 3
45483fd file() was removed in Python 3, use open() instead
5ab8ae7 Merge pull request #3511 from cclauss/patch-3
fa46d11 Merge pull request #3514 from pherl/rubyfix
29c24ab Merge pull request #3502 from pherl/pypi
1926636 Bump gem version for the next upload
958412e Old style exception --> new style exception
d1484cd Update CHANGES.txt
55d938c Update CHANGES.txt
98c6d04 Prefer system distributed binaries/libraries.
e243082 Update php version number to 3.4.0
82dd4b3 Update php c extension version number.
5d5df84 clean up
19a7e20 Update testpypi addresses.
80a37e0 Merge pull request #3495 from pherl/c++11
5e39ecc Merge pull request #3494 from drivehappy/clang_warning_macro
3d2f72b Merge pull request #3496 from pherl/mingw64
6654c8d Update readme
f619621 Merge pull request #3493 from pherl/cmath
d909834 static link for 32 bit build as well.
f7b3dd4 Update comments that cross compile is feasible now
fa086c8 First try static linking pthread
4a4c67b Add std::forward and std::move autoconf check
a23e198 Fixing warning under Clang 6.x (-Wexpansion-to-defined) where the macro expansion producing 'defined' was warning on undefined behavior.
3908b4e Fix cmath/math.h include with non C++11 libstdc++
1cc4ecd Merge pull request #3488 from pherl/changelog
3ae8c4c Update changelog for 3.4.x
eaeca0d Merge pull request #3485 from pherl/mingw
1bd2d1f Merge pull request #3484 from pherl/qualifier
651429b Fix comments
31b3bd9 Make compilers without ref-qualifier support happy.
b4c0cfe Add malloc cast
fd31899 implement remove strdup usage and implement our own
34ebca0 Adding missing imports for strdup
40d1855 Fix mkdir
564f02c Make win32_io only for MSVC
7afa796 Fix the declaration order in ming32
db125b8 Fixing io_win32 for MinGW32
e0d24cc Detect invalid tags with a field number of 0 in C#
d2f3adb Merge pull request #3481 from pherl/nowarning
ccb6b62 Merge pull request #3480 from bklarson/master
1b42347 Clean up typedefs for Atomic32/Atomic64
e8fc066 Make no warning test stricter.
9adb4e8 Merge pull request #3478 from pherl/warning
97d50e3 Make code free of missing-field-initializers warnings
35db267 Merge pull request #3473 from AlanBurlison/master
80e984e Merge pull request #3467 from thomasvl/bump_xcode_version
a68a800 PROTBUF-3394 Potential SIGBUS with UnsafeUtil.getLong
3afcded Merge pull request #3461 from TeBoring/3.4.x
176713d Merge pull request #3468 from vladmos/3.4.x
fae3816 Merge pull request #3454 from anandolee/master
06a825c Make .bzl files compatible with future versions of Bazel
d08c291 Merge pull request #3465 from vladmos/list_plus_equals
fe68821 Move travis to the Xcode 8.3 (8.3.3) image.
ba81c59 Fix up Xcode 8.3.x support.
4fc9304 Make .bzl files compatible with future versions of Bazel
8f4b8e4 Merge branch 'master' into 3.4.x
f14703c Update commit id in Dockerfile to reflect change in #3391 (#3459)
49b44bf Fix the bug in php c extension that setting one field can change anotherĀ field's value. (#3455)
21b0e55 Update PHP descriptors (#3391)
f5817b3 PY26 tests compatibility 1, Some tests in reflection_test PY26 raise TypeError but other versions raise ValueError for convert negative long to unsigned 2, Change compare exception type to compare exception str for testDuplicateExtensionNumber. Original code raise 'Double registration of Extensions' is not an instance of (<type 'exceptions.AssertionError'>, <type 'exceptions.ValueError'>) for PY26 cpp implementation
1ab5adb Merge pull request #3456 from giorgioazzinnaro/patch-1
a3e1752 Update third party addons with ProfaneDB
9150cd8 Skip setUpClass which is newly added in python2.7 for python2.6
d58df3b Add python 2.6 test back for cpp implementation. Json format issue was fixed in #869
c2f69d6 Merge pull request #3450 from pherl/invalidoffset
e243fd8 Merge pull request #3451 from pherl/fixtypo
39a91d3 Fix typo.
4cbbf33 Fix invalid offsetof warning.
25672c1 Add getClass for php Descriptor in c extension (#3443)
7781784 Add destructors for default instances to the shutdown code. Verified test succeed under draconian heap checker
53ae6de Merge pull request #3442 from pherl/csharpversion
6c64f11 Bump csharp version
e0288e7 Merge pull request #3438 from pherl/changelog
9df89cc Fixing HHVM Compatibility (#3437)
c15a326 Expose descriptor API in php c extension (#3422)
8a5208f Update change log
502624f Merge pull request #3419 from pherl/3.4.x
d77c8c5 remove the duplication
bcf1733 Adding the missing header
ebeb472 Export functions in io_win32.h in win DLL build
be73938 Change divideInt64ToInt32 to static (#3436)
d32f5b4 Removes unnecessary pass-by-references in PHP internal classes (#3433)
0724314 Merge pull request #3429 from king6cong/master
d6bd959 Merge pull request #3406 from ax3l/bg-3.4-cmake-pkgconfig
547d76e Add classpath for java example Makefile
9b505a9 Merge pull request #3421 from thomasvl/update_comment
9a4692d Update the comment on the message_type to cover what it should be.
5eb95ef Merge pull request #3420 from thomasvl/objc_proto2_conformance
3caf9fd Review feedback.
c2831a3 Add the proto2 message conformance support for ObjC.
9fd5e59 Generate the proto2 test file and link it in for ObjC.
21800ff Add a objc_class_prefix to test_messages_proto3.proto.
19b8c8b Update conformance tests again.
8d5f2c5 Merge pull request #3410 from adam-26/1745
12c186f Fix makefile.am
de6debc Fix conformance tests
e177739 Fix build files
9b8f658 Remove dependency on guava 20
d974cc2 Update conformance tests
f39d4de Merge remote-tracking branch 'origin/master' into merge
759245a Merge from master
bb86644 need for php math functions. used in mergeFromJsonString (#3409)
e9f4e8e Merge pull request #3407 from bklarson/master
451d061 Fix cycle dependency for repeated field not collected by gc (#3399)
4bff88e Merge pull request #3413 from pherl/3.4.x
ce44167 Merge remote-tracking branch 'origin/3.4.x' into vb
4ae94d6 Merge pull request #3414 from pherl/fixzip
eb6b332 Merge pull request #3412 from anandolee/3.4.x
02250a7 Omit the zip test if tools are not available
9c012ed Add __bool__ as well as __nonzero__ for python3
11b4d5e Update required version on pre-generated files
8b24feb Update pre generated files
7bb39be Update version number for 3.4.0
a484794 Use keys() instead of iterkeys() to be python3 compatbile.
72cc5a6 Merge pull request #3393 from pherl/3.4.x
b6da226 Put AddDescriptorsImpl() in anonymous namespace
a713b73 Merge pull request #3281 from BSBandme/ConformanceTestYilunChong
2b6db00 Fix quotation marks
a3a65b3 Fix issue #1745 - javascript allow dot in filename
f15185d Merge pull request #2969 from laszlocsomor/master
0d9a34c Add -Werror=missing-declarations to test builds
ebe659d Travis: Exclude CMake .pc files
2f3cf52 CMake: Install .pc Files
eef2edc Merge pull request #3403 from ax3l/topic-cmake-pkgconfig
74dcf44 Travis: Exclude CMake .pc files
668712c CMake: Install .pc Files
e8a32d0 Merge pull request #3401 from aschrijver/patch-2
d640cdd Updated outdated hyperlink
062df3d Merge pull request #3179 from bjwatson/fix-duration-typo
040f56e Merge pull request #3397 from acozzette/initialization
bba4c4a Merge pull request #3262 from snnn/master
417aae6 Fixed dynamic initialization for C++ lite
dd091aa Fix code to use values() instead
aa61bb0 compiles removal of newline (#3333) (#3370)
1876a27 Update filelist again
66c1dac Add lite and python extra_dist files
bf658c2 Add java and JS dist files.
988376c remove broken imports in JS
b07cdb6 Use itmes() instead of itervalues() to be python3 compatbile.
e45214e Fix distcheck
8084e03 remove profile
11b6661 update build file list
7986ca7 Update conformance tests
50aa4fe Merge pull request #3375 from TeBoring/3.3.x
3af881c Merge master into 3.4.x
8697530 Update csharp and php descriptor
09354db Merge from Google internal for 3.4 release
942a29c Merge pull request #3390 from danielgtaylor-isp/patch-1
6ec0b7e Merge 3.3.x into master
3370299 Merge pull request #3385 from anandolee/master
4b5b1e6 Add note about includes to README
9e745f7 Support PHP generic services (#3269)
b764e67 Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION for pure python comformance test
3354558 Merge pull request #3348 from matthauck/fix-gcc41-again
dd6e420 Merge pull request #3357 from bklarson/master
eb8e3d3 Merge pull request #3134 from lundefugl/javabug1
aaa2550 Merge pull request #3372 from dylanetaft/master
324b20a remove pass by reference for php setters (#3344)
29ff49f Fix Implicit Return Types (#3363)
36fcc2a Expand documentation in Readme.md
c78dbd7 Initial value in generated code cannot be used by c extension. (#3367)
ec3f5dc removes an accidental newline in printing for the php generator (#3333)
3a0382e Add map iterator for c extension (#3350)
d3bbf1c Add space between arrow and casted type (#3353)
6aa4b20 Merge pull request #3327 from htuch/fix-3322
71f2f0d Fix repository URL in C# project file
81142e1 Fix build when using -Werror=undef
727c0dc C#: Implement IReadOnlyDictionary<K,V> in MapField<K,V>
2130fea Fix map_field_inl.h for gcc 4.1
e05e777 Windows: support long paths
9ab7c73 Fix missing std::tr1::hash on GCC 4.1 (#2907)
126082c Add std:: namespace prefix to set and map (#3332)
b9c4daa Uncomment php tests (#3301)
f6ff32c Use consistent hash across NDEBUG/!NDEBUG builds.
bd5ab15 Merge pull request #2482 from andreaseger/fix_ruby_timestamp_accuracy
a9e7a15 protoc-artifacts: Bump JDK to 8u131
bceb830 add comments in makefile.am
6bd51a5 add Grpc Protobuf validation (#3311)
32c8ed3 change csharp failure list
30b4194 Merge branch 'ConformanceTestYilunChong' of github.com:BSBandme/protobuf into ConformanceTestYilunChong
7339c25 delete backup files
cbf7dfb fix php failing list and csharp generated proto
e264b20 Merge pull request #3315 from thomasvl/mutate_unknowns
b30dee3 Expose the initializer for unknown fields.
cdd524a Ensure leaveOpen is true when writing to a buffer
62d7fe5 Make Any easier to work with in C#
e82ba0b Merge branch 'master' into ConformanceTestYilunChong
726ba33 changed php's failing list
5085102 remove backup files
3adb054 add some test proto2 supported, add js proto2 supported, fixed some error
ecca6ea Add json encode/decode for php. (#3226)
a7d5be6 change php objc nodejs csharp ruby
fcb9268 change java to uniform message, revert TestValidDataForType's parameters
020a24d change cpp and python to uniform message
5a52b35 Merge pull request #3287 from sergiocampama/initialized
e55782f Add initialized as a reserved keyword as that's the actual property name
467c1cc fix csharp conformance test
db379e6 fix csharp conformance test
176bac6 Add scripts to build python wheel for linux. (#2693)
ff773c1 fix csharp
cd1dc3f add csharp support
3645021 add message set test case
06c9057 add objec support
5e7e2d3 revert ruby proto built files
cf7b6a4 delete backup files
6c59c25 delete binary
91da852 update .gitignore
0255431 revert .gitignore
696cf77 add java supported
0fa4e58 change ignore
18a0c2c add proto2 supported for cpp,python,nodejs,ruby,php
12acbc2 adds PHPDoc @return and @param for getters and setters respectively (#3131)
2ad74e1 add support for proto2
097bfb5 Merge pull request #3084 from lukaszx0/patch-1
dd7265e Merge pull request #3264 from TeBoring/php-bug
e3c807d Fix more implicit type conversions in public headers and generated code.
1a7e49d Merge pull request #2968 from ngg/cpp-proper-fwd
9c0b35c Enusre public header and generated code have no implicit converion.
4e67590 fix readme.md
58a3c74 add test_proto2_message.proto and change conformnace/makefile.am
f752d81 Merge pull request #3266 from mbrickn/patch-1
d07efba Updated links to use https
eca0f4e Merge pull request #3261 from thomasvl/super_oddcase
db45687 If we fail to get a descriptor just super the method resolving.
4987dda Fix a bazel build error on Windows
5555d3b Fix typos in comment
5532abc Merge pull request #3258 from TeBoring/3.3.x
5520b43 Update C++ generated code.
e7bcfc4 Update version number to 3.3.2
8ecae34 Merge pull request #3255 from TeBoring/3.3.x-3
3b1a875 Remove inclusion of ext/json/php_json.h. (#3241)
c344fe8 Oneof field should be serialized even it's equal to default. (#3153)
dba8928 Add ARRAY for reserved name (#3150)
703cd8e Switch to addEnumType to fix fatal error (#3225)
1325588 Updated upb to fix JSON conformance issues. (#3206)
c2fdef0 Merge pull request #3243 from yjjnls/master
73b7cc0 Merge pull request #3244 from thomasvl/complete_docs
5fd71ce ObjC: Document the exceptions on some of the writing apis.
72e293a Merge pull request #3240 from thomasvl/float_fun
8f367c0 replenish missed header files in install step
5729cf7 Remove inclusion of ext/json/php_json.h. (#3241)
dd19b87 Raise the number of digits used for floats.
710543d Merge pull request #3237 from calder/patch-1
491b320 Merge pull request #3236 from buchgr/bazel-links
888e287 Merge pull request #3235 from buchgr/java-target
4b36d40 Qualify string in java_options.h
36e63da bazel: Make compiled jars java 6 binary compatible.
d0e6f3b bazel: add bazel symlinks to .gitignore
91bf623 Fix php jenkins test (#3233)
8d97b3d Fix incorrect function call (#3232)
b9b34e9 Follows proper autoloading standards (#3123)
09d2994 Merge pull request #3228 from thomasvl/add_tvos_to_podspec
6ecf38f Add tvOS to the podspec.
c722c3d Merge pull request #3216 from traversaro/patch-1
9094bf0 Export symbols used in inline functions
9ba7d1c C++: Do not forward-declare dependencies in generated .h files
96095f3 Merge pull request #3176 from acozzette/fix-3114
c202b06 Merge pull request #3196 from matt-kwong/kokoro
0871e6a Add continuous testing config files for Kokoro
d4d41af Merge pull request #3191 from matt-kwong/kokoro
6156af1 Add MacOS and Linux tests to Kokoro
d555775 Merge pull request #3189 from thomasvl/objc_proto3_unknown_fields
2aeb4ab Merge pull request #3160 from meteorcloudy/winbuild
ddbe360 Merge pull request #3159 from yeswalrus/new-generate
1d0988b ObjC: Preserve unknown fields in proto3 syntax files.
516a81a Merge pull request #3190 from thomasvl/objc_IllegalZeroFieldNum
ecc0f54 Properly error on a tag with field number zero.
656dedb Merge pull request #3157 from yeswalrus/fix-version-check
7ccb251 Remove unused output_file variable from js_embed
6f32580 Add new file option php_namespace. (#3162)
df3f8cf fix check_and_save_build_option not correctly exporting build options
0336770 add protobuf_generate function, allows use of target_sources where available
e9c15d6 Ensure that for Java, imports of .proto files with empty packages works
fbaad36 Merge pull request #3169 from dmaclach/master
63a9728 Merge pull request #3170 from thomasvl/int64_map_issue
46f36d7 Fix some cases of reading of 64bit map values.
ea43e0c Optimize GPBDictionary.m codegen to reduce size of overall library by 46K per architecture.
0b059a3 Refactor cc options in BUILD file for Windows
d8c5865 Fix policy warning CMP0054
a183a0d Fix the check_and_save_build_option macro never evaluating to true
faa5398 fix check_and_save_build_option not correctly exporting build options
ae85cb8 Fix find module not working when no version number was given
d6470ab not to use std::random_device for map.Seed(). (#3133)
e222997 Merge pull request #3149 from KarrokDC/master
1e86ef4 Oneof field should be serialized even it's equal to default. (#3153)
282fb9e Add ARRAY for reserved name (#3150)
4d5daf4 Adds fluent setters for PHP (#3130)
4eb02fe Add headers as part of cmake project tested only on windows with visual studio 2015 as generator
4674cc7 Merge pull request #3113 from phst/master
95749d5 update csharp README and fix .NET 3.5 build error
aea4374 Issue 3112: Object class with fully qualified name
0b07d7e Add IncludeSource in csproj as per review comments
f26e8c2 Convert C# projects to MSBuild (csproj) format
40da1ed Removing undefined behavior and compiler warnings (#1315)
ba987a7 Merge pull request #3126 from mbrukman/fix-readme-formatting
c5125f3 Merge pull request #3117 from KarrokDC/master
d2c1865 Merge pull request #3103 from sergiocampama/perf
2465ae7 Adds serial and parallel parsing tests to check if parallel parsing is faster than serial parsing, which it should
6775570 Fix Markdown formatting in README.
979107e Improve fix for https://github.com/google/protobuf/issues/295
3b22761 show help if protoc is called without any arguments, pre-empts -h and --help to show a useful message instead of just 'Missing input file.'
bf04c83 Merge pull request #3085 from scpeters/issue_3059
8546620 Merge pull request #3104 from thomasvl/ext_registry_copy
49e4ba6 Fix ExtensionRegistry copying and add tests.
b28617b Merge pull request #2815 from devwout/ruby_json_emit_defaults
78cb804 change test for nanosecond accurate timestamps
ad203bc fix floating point accuracy problem in Timestamp#to_f
49a56da Update jenkins Java deps.
129a6e2 Revert guava depedency to version 19.
969e0be regenerate plugin and profile message code
26f0011 Use bool deterministic to suppress warning
474cca5 Add LICENSE in package.xml (#3083)
13f532e Merge pull request #3074 from xfxyjwf/3.3.x
82e50ba Workaround the docker bug when compiling artifacts
de6ae7d Fix upb load descriptor when no messages defined in prorto. (#3080)
2231931 Fix c extension for php7.1. (#3077)
757cc9f Update C++ generated code.
58538ea Update version number to 3.3.1
c2154e1 Merge pull request #3073 from xfxyjwf/3.3.x
d22493b Merge pull request #3064 from randomguy3/offset-type
9b82fce Workaround gcc < 4.5.0 bug
455b61c Merge pull request #3062 from Oppen/master
e062f70 Fix compilation
e82d81a Fix offset type to match the tables it is used in
25abd7b Add compatibility test for php. (#3041)
3c369dc Merge pull request #3057 from xfxyjwf/3.3.x
cd0efc0 Workaround gcc < 4.5.0 bug
99cf2ef Merge pull request #3056 from acozzette/cherry-pick-pr-2873
7378ec2 Add missing LIBRPOTOC_EXPORT.
3a5a072 Skip C# test in C++ only distribution.
8859c07 Add missing files to build files.
4833960 Merge pull request #3043 from acozzette/javascript
22c8772 Fix #1562 by using goog.crypt.byteArrayToString instead of String.fromCharCode.apply
dd0a233 Merge pull request #3055 from chrisn-arm/3.3.x
c3093d3 Fix issue 3046: compilation on alpine 3.5
f00e06c Removed mention of Buffer in byteSourceToUint8Array
a64497c Merge pull request #2873 from myitcv/fix_1562
bcb3506 Fix #1562 by using goog.crypt.byteArrayToString instead of String.fromCharCode.apply
2f4489a Merge pull request #3024 from acozzette/merge-3.3-to-master
286f059 added "objectivec" build target (#3033)
9053033 Merge remote-tracking branch 'remotes/google/3.3.x' into merge-3.3-to-master
067b1ee Merge pull request #3023 from acozzette/min
07c284f Fully qualify min as std::min in wire_format_lite.cc
a6189ac Add prefix to enum value with reserved name. (#3020)
cbd08cb Merge pull request #3018 from acozzette/using-namespace-std
54d1701 Merge pull request #3015 from buchgr/unused-consts
7c76ac1 Remove "using namespace std" from stubs/common.h
3c0855e Add a test case for nested enum, which was missed previously. (#3010)
b1c75bc Remove unused constants.
4920e27 Merge pull request #3008 from postmasters/patch-1
fba2acd Add nested enum descriptor in php rumtime. (#3009)
e64b618 Update php version number to 3.3.0 (#3001)
4777574 Add a link to dart-lang/protobuf
6fff091 Throw exception when parsing invalid data. (#3000)
f418b9e Merge pull request #2996 from xfxyjwf/3.3.x
4523c9c Allow proto files to import descriptor.proto (#2995)
478119f Fix python3 issue.
14afc3f Merge pull request #2992 from xiaogaozi/patch-1
f85eecb Add gogoprotobuf to third-party add-ons list
4c57e84 Prepend "PB" to generated classes whose name are reserved words. (#2990)
b97cd57 Add test for nested enum for php (#2989)
7be0882 Enum defined without package have incorrect class name. (#2988)
190b527 Make PHP c extension work with PHP7 (#2951)
357afc3 Merge pull request #2508 from yliu120/pass_default_env_to_protoc
0a93f67 Merge pull request #2987 from konsumer/patch-1
594f810 Merge pull request #2982 from mda000/issue2972
3055a02 Add node-protoc-plugin to "Other Utilities"
a3873ca Merge pull request #2985 from thomasvl/class_check_tweaks
f5a01d1 Tighten up class usage/checks.
2240a78 Simplify the Element dtor invocation when freeing elements in InternalDeallocate to avoid confusing the compiler when there's a class named Element already defined in the global namespace.
8aa927f Merge pull request #2950 from anuraaga/dev_rag
4323482 Merge pull request #2967 from xfxyjwf/3.3.x
5777259 Cherry-pick cl/152450543
cad0258 Cherry-pick cl/151775298
fc3ea97 Merge pull request #2955 from xfxyjwf/3.3.x
899460c cherrypick descriptor_pool.FindFileContainingSymbol by extensions (#2962)
bfeeb98 Add include for INT_MAX
e91caa1 Merge pull request #2949 from xfxyjwf/3.3.x
bf483df Allow unknown values for Map put*Value methods just like every other enum mutation method.
ee9c7f1 Cleanup reflection objects for map entry.
efec757 Merge pull request #2937 from anuraaga/dev_rag2
18c13c9 Merge pull request #2942 from xfxyjwf/3.3.x
21b0b3c Update generated code.
80f0c0a Update version number and changelog for 3.3.0
69bfde2 Merge pull request #2922 from anandolee/master
09328db Fix test for unexpected type url when parsing Any. Currently, the test fails since TestAllTypes doesn't have field '@type', which is the same test as testUnknownFields.
139fd0a Merge pull request #2933 from mharrend/patch-1
37c7b76 Merge pull request #2930 from anuraaga/dev_rag
662f978 Fix duplicate fields test. The repeated version is passing because null values in a repeated field are rejected and not testing what it wanted to. Also adds a oneof version that verifies the case of oneof fields of different names (currently only same name check seems to be tested).
cc3fa2e Merge pull request #2676 from acozzette/js-compatibility-tests
10ea251 Added compatibility tests for version 3.0.0
7e5f980 Split test protos into two groups
dd04ffb Adding default shell env
58373fa Fix error message for int64 parse error.
11c902e Add IntelliJ project to gitignore for java project.
bd74319 Update Java conformance failure list.
32ad5a3 Use "git reset --hard" to actually reset the code.
b7c813f Update jenkins Java dependencies.
c2b3b3e Update Java version number and dependency.
624d44f Update objective-c conformance failure list.
d582778 Fix C++ distcheck.
fe97d79 Fix MSVC DLL build.
fab8812 Update python conformance failure list.
c52e54f Update jenkins Java maven dependencies.
057a285 Update C# conformance failure list.
e47c068 Update python conformance failure list.
84f6954 Fix Java build.
c348d46 Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject()
acde165 Update BUILD file for C# tests.
32d7830 Fix C++ build for down-integration.
d36c0c5 Down-integrate from google3.
4a0dd03 Removes ignored const from return type (#2915)
258406b Merge pull request #2919 from thomasvl/drop_dispatch
130c166 Remove the use of dispatch_once that is heap backed.
ba3fa41 Merge pull request #2918 from thomasvl/xcode_8_3
558ba98 Add support for Xcode 8.3 to the build helper.
04c77c4 Merge pull request #2913 from thomasvl/conformance_ignores
d43eaf2 Fix gcc warning when using map (#2213)
5859932 Merge pull request #2914 from acozzette/nacl
f316375 Added a workaround to allow building for NaCl
8adf57e Add some new ignores for things generated in conformance.
b3f3e12 Merge pull request #2912 from thomasvl/objc_recursion_limit
ddb4388 Raise the recursion limit to 100 to match other languages.
d9e0119 Merge pull request #2858 from haberman/gopackage
c565e25 Merge pull request #1662 from haberman/jsconformance
7610f10 Merge pull request #2884 from anandolee/master
689e4bf Add FormatEnumAsInt support for Json Format. And scale JsonFormatter.Settings to multiple options.
373809e Merge pull request #2897 from cgrushko/patch-5
6f21e29 Compile the Java proto runtime with Java 6
1387a67 Update commit number in Docker to update composer dependency (#2869)
ffa932b Merge pull request #2861 from byronyi/#710
312e2db Update BUILD
db3ef48 Merge pull request #2860 from prehistoric-penguin/master
20181f6 Merge pull request #2854 from hesmar/attributesFix
4d273f2 Merge pull request #2870 from acozzette/memcpy-memmove
15b60bc Merge pull request #2867 from mojoBrendan/master
ea5ef14 Ruby: only link against specific version of memcpy if we're using glibc
c12cc34 Merge pull request #2837 from anandolee/master
6b27c1f Add file option php_class_prefix (#2849)
c0871aa Merge pull request #2848 from xfxyjwf/freebsd
e8e6aa2 Update delimited_message_util_test.cc
89eb4e5 Add option to preserve original proto field names
aec0711 Ruby tests compare parsed JSON instead of raw JSON
1eee320 Add use_snake_case_for_field_names option to JsonPrintOptions
c415a14 fix several issues
44dc555 Merge pull request #2866 from xfxyjwf/nano
ddc0096 Add a notice for nano.
1b0db1c Removed obsolete comments and added docs.
0df2028 Properly regenerated descriptor.proto.
89c3c45 Merge pull request #2859 from haberman/junit-dep-scope
2957703 Merge pull request #2847 from haberman/ruby-toh
0fad0e1 Merge pull request #2794 from acozzette/jspb-extensions
acaa940 add delimited_message_util.cc to libprotobuf.cmake
7008a88 add LIBPROTOBUF_EXPORT to make msvc happy
cb3e84b migrate delimited messages functions to util package
33cc25f Remove duplicated copyright statement
496cd48 Changed scope of Java deps to "test".
e62e30c Changed go_package for plugin.proto.
4842363 Merge pull request #2023 from odeke-em/fix-print-help-to-stdout
e77a09e Incremented Ruby version number to 3.2.0.1
8c40b51 Ruby: update Gemspec.
97cbc42 Fix libprotoc.cmake to generate well_known_types_embed.cc
f23869c Bug fix: When encoding, negative int32 values should be padded to int64 (#2660)
014a550 Ruby: build packages for Ruby 2.4.
c57c77b Merge pull request #2829 from afrantzis/hide-unnecessary-library-symbols
324a299 Made formatting more consistent.
ed0ef54 Merge pull request #2846 from acozzette/bytestream-comment
d18df81 Merge pull request #2855 from thomasvl/copy_note
5e4f14f Document deep copy in the header
b4b855c fix attributes warning
416f909 Fix freebsd build.
9c6b8cb Ruby: fixed Message#to_h for map fields.
95b4427 Build system fixes for JS conformance tests.
43f2db7 Merge pull request #2843 from haberman/check
746ca59 Updated an outdated comment in bytestream.h
874e382 Replace CHECK() with GOOGLE_CHECK().
8df69f0 Conformance test for JS now work, though 15 tests fail.
f0a5c10 Merge pull request #2836 from xfxyjwf/i894
ddfc86b Merge pull request #2835 from pherl/javaep
13d165d Hide unnecessary exported library symbols
d59592a DefaultValueObjectWriter should populate oneof message field
c94555f Double-quote file paths in extract_includes.bat.in
f4f31e7 Suppress the last unchecked warning.
a69bc9d Merge pull request #2822 from anandolee/master
f54fb9d Merge pull request #2832 from pherl/javaep
e11cd3e Merge pull request #2818 from xfxyjwf/i1470
6044b24 Make //:protobuf_python have correct __init__.py.
92064a4 Merge pull request #2824 from xfxyjwf/i1415
cd6eb91 Merge pull request #2826 from xfxyjwf/i1374
81f4fe5 Merge pull request #2827 from xfxyjwf/i1251
81fe52f Fix java code according to error prone.
616e68e Repeated/Map field setter should accept a regular PHP array (#2817)
ae220cd Add auto detect for generated code of WKT protos, addressbook.proto and conformance.proto
03c8c8b Update comments for setSizeLimit.
a1bb147 Merge pull request #2825 from pherl/javawarning
1ece7c0 Add missing thread dependency in cmake.
009e491 Fix GeneratedMessageV3 warnings.
da00355 Merge pull request #2809 from xfxyjwf/i2464
61e87f3 Use per-type table to lookup JSON name.
7c75344 Fix lint warnings in the javalite branch.
cad6a51 Merge pull request #2819 from haberman/pythonexcept
3e6245e update_failure_list.py: fixed Python "raise" statement.
075475f Don't expose gson exceptions in JsonFormat.
bbfb9d5 Merge pull request #2804 from acozzette/ruby-memcpy
8e465dc Merge pull request #2810 from xfxyjwf/i1994
af2d5f5 Merge pull request #2775 from xfxyjwf/fixmajor
9afacb4 Merge pull request #2814 from pherl/javadeprecate
baceff7 Add annotations for deprecated messages in Java
008dc92 Ruby version optionally emits default values in JSON encoding.
9fa4031 Ruby: wrap calls to memcpy so that gem is compatible with pre-2.14 glibc
c311543 Avoid redundant type casts for oneof bytes fields.
4ae8656 Make JsonFormat locale independent.
fa17880 Merge pull request #2602 from GreatFruitOmsk/issue-2428
920af75 Fix Bad Link for Common Lisp
dd8d5f5 Rename encode/decode to serializeToString/mergeFromString (#2795)
769b693 compiler/cli: PrintHelpText prints to stdout instead of stderr
2b7430d Merge pull request #2793 from keveman/master
f6d8c83 Merge pull request #2613 from aausch/fix_memory_leak
21b58b5 Removed a stray return statement, causing compilation error.
651ba62 JS: ensure that extension values are serialized even if they're falsy
06f9f60 Detect if Descriptor.cs changes for csharp
f873d32 Added JavaScript conformance tests.  All tests pass!
27b1f2b WIP.
0c0a887 Merge pull request #2751 from keveman/master
008ff03 Merge pull request #2784 from acozzette/log-2-floor-int
6837b2d Added comment explaining the protobuf_headers target.
af13bff Detect if Descriptor.cs changes for csharp
8610d0a Merge pull request #2755 from xfxyjwf/rubycomp
352526c Merge pull request #2785 from thomasvl/threading_race
2d1c5e2 Handing threading race resolving methods.
938206d Return uint32 from Log2FloorNonZero64
a7e3b0a Merge pull request #2774 from acozzette/closure-builder
8b182cc Disable static analyzer for message semaphore creation (#2748)
6011d7c Fix gcc 4.1 build (#1035) (#1913)
25ecd55 Change hint type to `const void*` (#2568)
bcbaabe Add mergeFrom method on Message (#2766)
671e075 Use closurebuilder.py in favor of calcdeps.py for compiling JavaScript
7339fc0 Merge pull request #2674 from acozzette/js-test-cleanup
b7f25d4 Undef major/minor if they are defined as macro.
aff9d9d Removed log statement from writer_test.js
5274d6e Merge pull request #2770 from xfxyjwf/fixcmake
83b0cc9 Merge pull request #2772 from sschuberth/master
606cb7e There might be duplicated enum values when allow_alias is true. Add PreferredAlias into OriginalNameAttribute to remove the duplication (#2727)
902af08 Prefer the term "3-Clause BSD License" over "New BSD License"
6395a1c Fix links to the New BSD License in meta-data
ffde972 Remove the use of C++11 features.
9118ad6 Add Ruby compatibilty test against 3.0.0.
d41c47f Merge pull request #2733 from wmamrak/patch-1
8d61f9c Merge pull request #2729 from MarcelRaad/fix_inline_msvc12
b4b0e30 Merge pull request #2355 from xfxyjwf/fixjson
8387b88 Merge pull request #2732 from AsturaPhoenix/master
66c64e7 Merge pull request #2747 from liutikas/master
8c8b8e6 Merge pull request #2734 from msabramo/patch-1
72b82e6 Merge pull request #2630 from blodan/master
963473b Merge pull request #2753 from thomasvl/recursive_drop
d071766 Add GPBMessageDropUnknownFieldsRecursively() and tests.
2d430f8 Added a header only cc_library target for the protobuf library.
17174b5 Updating README
f83d129 Upgrading test-related libraries
c9b2c8f Fixes for .NET 3.5 compatibility
a434bfc Fix compiler warnings about unused variables in generated_message_reflection.h
1a8cbfd Merge pull request #2736 from na-ka-na/master3
172e0a6 Add an option to always print enums as ints in Json API
86208c5 README.md: Make docs URL a link
37bd5d5 Disable MSVC warning C4309
01a05a5 const FieldDescriptorCompare
8f9c0a4 Fix unresolved symbols with MSVC12 and /Zc:inline
a9ab38c Merge pull request #2722 from ckennelly/unified
8af35f2 Keep loop bounds in a local variable for string fields.
a6c30d9 Keep loop bounds in a local variable.
9db5b11 Work with truncated tag numbers.
0026dff Expose rvalue setters for repeated string fields.
38b1440 Merge pull request #2663 from ckennelly/varint-size
15360e5 Merge pull request #2689 from ckennelly/aliasing-fixed32-fixed64
38c238e Improve support for plugin parameters.
d2dfe46 Merge pull request #2609 from yixiang/patch-1
3f6f73b Merge pull request #2701 from anandolee/master
ed423c2 Merge pull request #2451 from podsvirov/json-primitive-map
aa78aeb Merge pull request #2704 from liutikas/master
74eb9a0 Add clear method to PHP message (#2700)
46c022a JsonUtilTest: Add ParsePrimitiveMapIn subtest
9079079 Fix compiler warnings about unused variables in wire_format.h
ef927cc Switch to gcc atomic intrinsics for macOS and delete the file that uses (#2699)
7288689 Add csharp compatibility tests against v3.0.0 and run on Travis.
1d2736f Merge pull request #2656 from pcj/patch-1
9f09d18 Add proto and test files for csharp compatibility tests against v3.0.0. All the files are copied from 3.0.0 (JosnFormaterTest was deleted)
c6e0d0e Merge pull request #2647 from anandolee/master
42e1e2a Fix python compatibility test when a new generated code imports an old version(2.6.1 or older) generated code.
e844510 Merge pull request #2692 from cgrushko/patch-3
65a4d20 Update load() statement to latest style
a60cc08 Merge pull request #2691 from cgrushko/patch-3
cba04b1 Implement json encoding decoding for php. (#2682)
6fffd4a Bazel can build protobuf when it's not in the root
56da828 Avoid aliasing CodedInputStream::buffer_ when parsing little endian integers.
c002743 Add fixed version to phpunit used in travis (#2673)
36f51f9 Merge pull request #2681 from sergiocampama/spaces
e7f5c9d Removes trailing whitespaces
5a3405c Update upb for php. (#2662)
bd29f86 Fix CopyTo argument validation
36f68e0 Inline branch-less VarintSize32/VarintSize64 implementations.
3975664 Add conformance test for php (#2655)
7b54b34 Add bazel protobuf resources
7f3e237 Merge 3.2.x branch into master (#2648)
9d3288e Merge pull request #2226 from kchodorow/master
2c36cc3 cache generated classes, optimization and quick workaround to memory leak
afc59ab C#: Implement IReadOnlyList<T> in RepeatedField<T>
87e4976 Merge pull request #2639 from anandolee/master
1ee09c8 python: do not include internal 'strutil.h' header
a83ac86 fix compile error on centos in metadata.h for constructors. (#2599)
a323f1e Oneof accessor should return the field name that is actually set. (#2631)
ccb76ff Add Oneof custom options test
5af0b54 Merge pull request #2619 from anandolee/master
1f09786 Merge pull request #2633 from anandolee/jieluo_branch1
ea51149 Add python compatibility tests against v2.5.0 amd run on Travis.
c15217f Allow OneofOptions to be extended in proto3.
c2a5669 Merge pull request #2626 from sergiocampama/8_3
32fa55e FreeBSD compatibility
4e7ecde Update genfiles paths to work with a different execroot arrangement
3d7b42d Adds nullability modifiers to resolve Xcode 8.3 warnings
140e28d Add python compatibility tests against v2.5.0: copy tests and proto files from v2.5.0
0aa5af3 Merge pull request #2614 from acozzette/gzip-output-stream-options
a101fa5 Set LIBPROTOBUF_EXPORT on GzipOutputStream::Options
e41b667 Undef TYPE_BOOL to avoid conflict with iOS.
047575f Support custom options in C#
eed9951 Merge pull request #2591 from thomasvl/objc_timestamps_take2
24908e1 Update AbstractMessage.java
d0bc096 Timestamp helper fix, Duration helper cleanup.
c9cd6ac Merge pull request #2587 from google/revert-2586-objc_timestamp
1651342 Revert "Fix Timestamps with dates before the Unix epoch that contain fractional seconds."
cf477d4 Merge pull request #2586 from thomasvl/objc_timestamp
adcccd0 Fix Timestamps with dates before the Unix epoch that contain fractional seconds.
feb78fb Merge pull request #2584 from cgrushko/patch-2
e4baf3f Add a proto_lang_toolchain for Java
e53dd99 Merge pull request #2529 from wackoisgod/master
fac90c6 Update AbstractMessage.java
75ac397 Fixing code formatting issues
effcb13 Merge branch 'master' of https://github.com/wackoisgod/protobuf
228d242 Merge pull request #2567 from acozzette/distcheck-fix
fb71df9 Add ByteString.FromStream and ByteString.FromStreamAsync in C#
e76d91a Add global.json file to pick dotnet core SDK version.
0bdf4a6 Fixed "make distcheck" for the Autotools build
2bddffc PHP fix int64 decoding (#2516)
2c16f69 Fix generation of extending nested messages in JavaScript (#2439)
ffa71f8 A few more cases for binary conformance tests. (#2500)
1041710 Merge pull request #2565 from acozzette/cross-compilation
24f0d56 Merge pull request #2563 from thomasvl/autocreator_tweaks
988ffe0 Minor fix for autocreated object repeated fields and maps.
2deb139 Merge pull request #2544 from tiziano88/master
17a8a76 Merge pull request #2536 from jbrianceau/fix-js-embed-include-style
c55175c Merge pull request #2564 from acozzette/arena-nc
a592052 Removed arena_nc.cc and arena_nc_test.py
b40d318 Fixed cross compilations with the Autotools build
f3e86fd handle sanity check for repeating enums correctly
4cb113a Fixed issue with autoloading - Invalid paths (#2538)
30250cd Add link to Elm proto plugin
5f65ee6 Merge pull request #2542 from jbrianceau/fix-embed-cc-warning
4455cdf Fix include in auto-generated well_known_types_embed.cc
05b019a Fix warning in compiler/js/embed.cc
f52e188 Merge pull request #2523 from jbrianceau/init-index-in-metadata
137dc02 Merge pull request #2525 from camillol/lite
abe1725 simpler, cheaper callback to LazyStringOutputStream
4e229c8 add MethodResultCallback_0_0
15a15e3 Init index_in_metadata_ without condition
6c021b3 Added the support for class level deprecation which will in turn also deprecate any fields that are currently using that type
d948b66 Merge pull request #2521 from acozzette/fix-bazel
5731ca5 Added well_known_types_embed.cc to CLEANFILES so that it gets cleaned up
ee0a243 Updated Makefile.am to fix out-of-tree builds
d1e7bd9 Added Bazel genrule for generating well_known_types_embed.cc
cdc2766 Merge pull request #2506 from ckennelly/rvalue-setters
bb2c6b2 Merge pull request #2505 from ckennelly/master
c64830b unwrap descriptor class before comparison of RepeatedField types
fb15862 Merge pull request #2517 from acozzette/js-embed
98d89d4 Fixed "make check" for cmake build
1b3a0c1 Auto-generate well_known_types_embed.cc
183d31c Add rvalue setters for non-arena strings on C++11.
f39cf88 Merge pull request #2227 from KindDragon/3.1.x
b18bc9b Give C# ByteString a sensible GetHashCode implementation.
ef61a9d add a key to ctx.action dict to prevent protoc losing the default env
ba63fa7 Remove spurious NULL checks in ArenaStringPtr::CreateInstance.
a95e38c Merge pull request #2499 from ckennelly/master
a902e25 Define LANG_CXX11 for port.h and use this to guard C++11 features.
83d681e Merge pull request #2495 from acozzette/android-hash
d1c1dad Merge pull request #2498 from sergiocampama/enum
c68fc58 Fixes and expands comments on how to use GPB_ENUM_FWD_DECLARE
2ff42dc Added conformance testing for binary primitive types. (#2491)
f983302 Merge pull request #2496 from xyzzyz/fix-overflow
837fd6b Merge pull request #2493 from jbrianceau/add-missing-climits-include
f77b7d9 Merge pull request #2484 from ngg/uwp_build
4c5d3ed Fix integer overflow in FastUInt32ToBufferLeft
5587562 Removed Android-specific code from stubs/hash.h
7b220f3 Add missing include in embed.cc
9d709f4 Merge pull request #2487 from jtattermusch/csharp_leading_whitespace
83c728a Add missing includes
eb455ce Merge pull request #2471 from jbrianceau/fix-include-style
6b86a89 Merge pull request #2490 from xfxyjwf/icon2
4c252dd Add a badge for bazel build status.
ec021f5 Add support for Windows ARM builds
29fb87e Merge pull request #2454 from pongad/go_package
fda9049 remove leading whitespace in C# xml comments
277a8b6 generate_changelog.py: flush output so piping works correctly.
8494846 Merge pull request #2476 from acozzette/generated-message-reflection-fix
dc11940 Merge pull request #2475 from sergiocampama/rvm2
e19f3b5 Use uint32 in GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET macro
1ac8944 Reenable cocoapods objc test and remove unnecessary workaround for rvm
e43f73e Merge pull request #2473 from thomasvl/update_xcodes
70e21d7 Mark objectivec_cocoapods_integration as failing
bc9d077 Skip benchmark test if cmake isn't installed.
2754586 Xcode 8.1 support
e3da722 Fix #include in cc files
243ebec Merge pull request #2468 from sergei-ivanov/patch-1
d8f54c4 Disable jruby test. (#2469)
09dc933 Update third_party.md
e3e38b8 Update commit id in Dockerfile to trigger update. (#2467)
4474c04 Merge pull request #2462 from jbrianceau/fix-comp-builds-part2
6b4eee4 Merge pull request #2461 from jbrianceau/add-missing-include-in-embed-cc
34a1b6e Merge pull request #2394 from cwelton/formatting
46ae90d Make php generated code conform to PSR-4. (#2435)
631f461 Merge pull request #2466 from thomasvl/deprecation_followup
4c84b47 Merge pull request #2460 from sergiocampama/c11
dad775b Improve ObjC deprecated annotation support.
e219be7 Regenerate descriptor proto
b1295ee C++: export _xxx_default_instance_ symbols
867dbac Add missing include in embed.cc
c836ad4 Merge pull request #2459 from acozzette/android-logging
1d91c25 Include -std=c++11 when compiling protobuf if available.
2f29f0a Send all protobuf logging to logcat by default on Android
057389c Ruby: removed redundant RepeatedField#slice. (#2449)
850d573 Merge pull request #2407 from jbrianceau/fix-comp-builds
788d14a Export symbols used in inline functions
bb77cbf update descriptor.proto's go_package
607b921 Merge pull request #2437 from xfxyjwf/plugin
1a56251 oneOf fix for JsonFormat includingDefaultValueFields
ced8f73 Add version number to plugin protocol.
0509072 Merge pull request #2445 from ramrunner/master
c664b66 Merge pull request #2442 from pherl/fix-bazel
4cc160e when on OpenBSD we include the correct headers for endianess and check the apropriate defines
f92b455 Add missing files.
f1ce60e Factored Conformance and Benchmark test messages into shared test schema. (#1971)
4280c27 Merge pull request #2436 from cgrushko/patch-1
45d92ae Add a proto_lang_toolchain() for cc_proto_library
6b60ddd Merge pull request #2431 from saintstack/2228v2
7550bcd Change CodedInputStream#DEFAULT_SIZE_LIMIT from 64MB to Integer.MAX_SIZE (0x7FFFFFF) #2228
f8ca3ac Generate phpdoc in php generated files. (#2406)
34dc96b LIBPROTOC_EXPORT added to others functions in csharp_names.h and objectivec_helpers.h
b790da5 Missed LIBPROTOC_EXPORT for GRPC added
851cb81 Merge pull request #2429 from thomasvl/issue1833_swift_prefix
f813bd9 Add a swift_prefix file option.
39f9b43 Merge pull request #2403 from google/down-integrate-with-msvc-fix
65479cb Fixed Ruby tests for JRuby 1.7
259dd7e Updated descriptor_pool.py to be compatible with Python 3
db35fe7 Add a "u" suffix to tag numbers in generated code
a7f300d Fixed descriptor_pool_test.py for Python 2.6
c950471 Merge pull request #2404 from wiktortomczak/master
0fa31b2 Support grpc plugin in py_proto_library
a41090e Updated failure_list_java.txt for Java conformance test
72002d8 Merge pull request #2400 from acozzette/jspb-test-fixes
fda876a Added back in binary serialization round-trip in message_test.js
b763246 Merge pull request #2398 from jbrianceau/no-static-init-define-fix
04bd614 Merge pull request #2392 from xfxyjwf/fixdown
40f3586 Fixed remaining JSPB test failures
315350b Updated message_test.js so that it does not depend on fromObject
b4dd686 Updated enum names in test.proto to avoid conflicting with testbinary.proto
a5c30ce C++: Fix use with GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
7807932 Restore jenkins files.
599613e Update EXTRA_DIST lists.
1f077a0 Update conformance failure lists.
530ae30 Add back missing LIBPROTOBUF_EXPORT.
1673389 Updated libprotoc.cmake
5d63097 Merge branch 'master' into down-integrate-with-msvc-fix
5a76e63 Integrated internal changes from Google
cd315dc Merge pull request #2383 from snapsam/patch-1
44edefa Merge pull request #2382 from zhsyourai/master
d571d39 Update README.md
14c147e Add LL to large constant
cb54caf Add tests to demonstrate json parsing for null Timestamp and Duration types
99564c3 Rename Empty to GPBEmpty in php generated file.
fc27ead Merge pull request #2362 from wujingchao/patch-1
a3dfbe6 Merge pull request #2378 from ianfhunter/patch-1
01d321c Merge pull request #2367 from jbrianceau/add-missing-include-in-message-lite-cc
130bb07 typo
83d6411 Fix jenkins tests.
bf37971 Merge pull request #2323 from marcinwyszynski/master
c6f3d70 Merge pull request #1907 from evokly/js-utf8-fix
bd850a2 JS: Well, this is the right place for surrogates.
292c2c9 JS: Re-added comment, moved surrogates code to the right place
6e93fa4 Merge pull request #2366 from jbrianceau/reland-fix-include-js-generator
a95d052 Merge pull request #2368 from jbrianceau/fix-json-style-in-project-json
3c0e0ce Fix csharp/src/Google.Protobuf.Test/project.json
aac9ed8 Add missing include in message_lite.cc
3316062 Fix #include in js_generator.cc
74a636a Move variable declarations before actual code
0c0f7e2 Merge pull request #2364 from haberman/jslicense
5d9dbe3 Fixed JavaScript license declaration.
abeff7b Class is final but declares protected field
a30e5af Merge pull request #2358 from ckennelly/master
e02cb2b Resolve old TODO for StringTypeHandler.
8a4b2c5 Merge pull request #2353 from guptasu/master
df56736 Merge pull request #2357 from D3Hunter/master
ed08341 #2356 : fix ExceptionInInitializerError on IBM J9
bd158fc Speed up JSON parsing.
df83907 Fix php c extension on 32-bit machines. (#2348)
9f75c5a Merge pull request #2337 from sergiocampama/deprecation
fce8b6b Made helper code also consider package name 'proto2' when dealing with MessageOptions.
e75cf40 Fixing references to the removed atomicops_internals_pnacl.h file.
ce5160b Merge pull request #2332 from Kwizatz/master
d584321 Merge pull request #2327 from ctubbsii/fix-maven-compiler-plugin
1f2dbc8 Implement RepeatedFieldIter for c extension. (#2333)
ecc460a Renamed the pnacl version of atomicops.h into C11 atomic, and flagged the mac version to that if atomic is enabled
975d577 Added explicit cast to avoid size warning on Win64.
0d7199e Merge pull request #2329 from acozzette/unused-parameter
ca800ea Merge pull request #2330 from manupsunny/master
089aaa9 Fix message for InvalidProtocolBufferException
8785004 Fix unused parameter warnings in arena_free
eb7f3a3 Use latest maven-compiler-plugin (2.6.0)
7bd11fc Merge pull request #2301 from jbrianceau/arm-atomic-kuser-helpers-fix-v2
4c310d7 Update conformance test failure list
50a37e0 Change JSON field name formatting
cb81314 Fix copy pasta in test
3bdaaa5 More Ruby-eqsue interface
93a4fa2 Merge pull request #2302 from jbrianceau/generic-gcc-atomics-strong-cmpxchg
750b9e2 Merge pull request #2318 from mavrukin/patch-1
4d813de Fix compiler warnings when running :protobuf_test
8fcd24b Merge pull request #2307 from sinzianag/swift_protobuf
ea928a1 Merge pull request #2309 from thomasvl/note_about_coding_support
98c0185 Add note about extension use and Coding support.
9819b72 Adding Apple's Swift Protobuf
a5a2c1d generic atomicops: Use strong compare_exchange
4587a3f [arm/gcc] Don't rely on KUSER_HELPERS feature for atomics
d58b92a Adds pushLimit: and popLimit: into GPBCodedInputStream (#2297)
795976e Trigger update of docker for new changes in #2282. (#2288)
e9d9e56 Merge pull request #2290 from ramrunner/OpenBSDsupport
bfc1299 define no_threadlocal on OpenBSD
734930f Merge pull request #2284 from pherl/plugin_opt
2e314a6 Add comments about converting directives into PluginName
59cd5d0 Support extra parameters for plugins.
51c5ff8 Fix pure php implementation for 32-bit machine. (#2282)
58580da Merge pull request #2274 from nmittler/gae
c0f95c6 Hacking ByteBufferWriter to work with GAE
9c6940f Merge pull request #2264 from rshin/master
7c913d8 Use -DPROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
df5841f Place Python extensions correctly in Bazel build.
008b5a2 Merge pull request #2254 from JasonLunn/patch-1
9ec7a47 Use git clean before installing via bundler
993d604 Merge pull request #1959 from abergmeier-dsfishlabs/feature/cpp
ad88f90 Merge pull request #2251 from TeBoring/master
686a19c Merge 3.1.x into master.
e28286f Add 32-bit machine test on jenkins. (#2245)
afaa827 Merge pull request #2246 from fweikert/patch-1
c2b3e70 Declare all inputs of protoc action
60d95f3 Fix the bug that message without namespace is not found in the descriptor pool. (#2240)
0321baf Merge pull request #2203 from mrry/msvc_fix
7332ffb JS: Replaced fromCodePoint/codePointAt with fromCharCode/charCodeAt because of functions limited availability, fixed typo in tests.
fd046f6 Merge pull request #2234 from TeBoring/master
daba665 Fix python_cpp test on Mac. Link staticly when building extension, so that the extension doesn't require installing protobuf library. (#2232)
5be6325 Add csharp/build_tools.sh for dist check.
63448e6 Fix compile error for php on Mac.
4f3d20a Fix segmentation fault when ZTS is defined.
1e5d4ba PHP: fix ZTS tsrm_ls errors (#2189)
c96dd66 Add test for php zts build.
447dee1 Prepare jenkins for testing php zts build.
7047761 Do strict enum name checking only for proto3
34cdaf4 Add travis test on Mac for php.
c8bd36e Test php5.5_c test on jenkins
c0719f0 Trigger automated tests for php.
91bbff2 Set up environment for php automated tests.
fd332d1 Add php test script for automated tests.
89db7ce Add script to build Google.Protobuf.Tools for csharp.
f2eeaf7 Added alias getFieldProto3 as used by older generated code.
4a4a162 Fixed references to foreign nested messages with CommonJS-style imports
0bf5482 Fixing inconsistent php version number.
ae9455c Fix MSVC stack overflow issue.
e0a6e52 Add php files for make dist.
17cc42a Update change log for 3.1.0 (#2173)
8db25a2 Force a rebuild of Jenkins docker image.
a41349d php: support 5.5.9 for pecl extension (#2174)
39685f6 Fix VS test failures.
2937c67 Use "appveyor DownloadFile"
b155958 Update php supported version.
9e260a3 Reduce test length to avoid stack overflow on VS.
1c4cf0e Fix python cpp.
460e7dd Fix Visual Studio compile issues.
4cf0722 Fix default instance destructor
f9f3c35 Update version number.
0c78525 Bump library version to 11
e62d1f1 Add back removed descriptor field.
fac876d Modify php api version and minimum supported php version.
9372292 PHP: support 7.0 on PHP implementation (#2162)
f933d10 Update version number.
04d72c2 Fix java compatibilty tests.
9d4657a update files to include php generators
633fdfb Update minimum support php version to 5.5
9526385 Fix bugs for internal integration.
89d8e43 Fix travis, jenkins environment issues.
7fecfdb Added new has_bits.h file to cmake/extract_includes.bat.in (#2152)
f7bb847 Fixed quadratic behavior in JSPB deserialization of repeated fields (#2117) (#2146)
31dd499 Fix bugs for csharp and ruby for internal integration.
23d4688 Fix python bugs for internal integration.
93007e1 Bump library veriosn to 3.1
fe1aaad Fix bugs for internal integration.
15f4db6 Bump version number to 3.1.0-alpha-1.
af62fde Fix for maps_test.js in JavaScript. (#2145)
e3f0689 Fix bugs for internal integration.
cc8ca5b Integrate internal changes
337a028 Merge pull request #2236 from hochhaus/master
b2b6584 Silence compile warnings in bazel
bc3bff1 Fix python_cpp test on Mac. Link staticly when building extension, so that the extension doesn't require installing protobuf library. (#2232)
c0c3aee Merge pull request #2229 from xfxyjwf/fixbuild
431cee6 Remove inexist files from build.
d947308 update files to include php generators (#2165)
b0d62dd Add csharp/build_tools.sh for dist check.
96e2d76 Fix compile error for php on Mac.
75b6988 Fix segmentation fault when ZTS is defined.
52ab3b0 PHP: fix ZTS tsrm_ls errors (#2189)
71e5994 Merge pull request #2193 from acozzette/common-js-fix
60bc203 Merge pull request #2199 from JasonLunn/patch-1
2d897c8 Add test for php zts build.
3a055be Prepare jenkins for testing php zts build.
640c947 Merge pull request #2204 from acozzette/enum-names
149659b Do strict enum name checking only for proto3
858db7a Add travis test on Mac for php.
4d87527 Merge pull request #2218 from thomasvl/xcode8_updates
bcb32c0 Test php5.5_c test on jenkins
297449a Update the ObjC projects for Xcode 8
fe1d0a1 JS: Added string encoding/decoding tests for UTF-8
23f108d JS: Fixed UTF-8 string encoder/decoder for high codepoints.
350d494 Merge pull request #2206 from acozzette/gitignore
dae50dc Trigger automated tests for php.
f17528a Set up environment for php automated tests.
1baaedf Add php test script for automated tests.
25dbc8b Updated .gitignore with Java and JavaScript build artifacts
6005648 Add development dependency requirements
1d2c7b6 Fix MSVC build when HAVE_LONG_LONG is defined.
ee19a7c Remove hanging reference to Gemfile.lock
d94ff41 Delete Gemfile.lock
07f3cab Set platform to "java" under JRuby
b9bad65 Add script to build Google.Protobuf.Tools for csharp.
3b88a4a Merge pull request #2196 from haberman/nodefix
3d598ee Merge pull request #2197 from thomasvl/swift_docs
fb85b43 Drop the swift docs directory (and content).
8b54280 Added alias getFieldProto3 as used by older generated code.
c4d7012 Fixed references to foreign nested messages with CommonJS-style imports
3f59452 Merge pull request #2192 from google/3.0.x
787f3fb Fixing inconsistent php version number.
c531b49 Merge pull request #2181 from google/jtattermusch-patch-2
530eede Update README.md
4d3e4cf Fix MSVC stack overflow issue.
a428e42 Add php files for make dist.
e7269aa Update change log for 3.1.0 (#2173)
87d61e4 Merge pull request #2175 from xfxyjwf/fix_json
5248f61 Force a rebuild of Jenkins docker image.
907a075 php: support 5.5.9 for pecl extension (#2174)
3c88e1b Fix VS test failures.
c454b44 Merge pull request #2171 from xfxyjwf/fix_json
73c8723 Use "appveyor DownloadFile"
18f336b Update php supported version.
f6b4d18 Reduce test length to avoid stack overflow on VS.
411968d Fix python cpp.
37c3d05 Merge pull request #2167 from xfxyjwf/fix_vs
0798d91 Fix Visual Studio compile issues.
3bfc09d Merge pull request #2170 from pherl/3.1.x
f184cb6 Fix default instance destructor
34996c3 Merge branch '3.1.x' of github.com:google/protobuf into 3.1.x
a289d43 Added C++ benchmark. (#1525)
d9ff3ef Merge pull request #2153 from haberman/generatechangelog
8c88762 Update version number.
94bbeb4 Bump library version to 11
1b7a844 Add back removed descriptor field.
9cb812f Modify php api version and minimum supported php version.
11433f7 PHP: support 7.0 on PHP implementation (#2162)
39a2a25 update files to include php generators (#2165)
2649844 Update version number.
5270e93 Fix java compatibilty tests.
923314c update files to include php generators
1bf97d8 Merge pull request #2159 from google/jtattermusch-patch-1
da7c026 Update README.md
ca21b28 Merge pull request #2157 from google/csharp_remove_beta_notice
ca8120c Update README.md
8352d52 Update minimum support php version to 5.5
bee5213 Fix bugs for internal integration.
525c632 Fix hash computation for JRuby's RubyMessage
b8e7e89 Fix travis, jenkins environment issues.
b28ab73 Fix gson dependency. gson 2.3 has internal bug that it doesn't work with some versions of maven.
142e2fa Merge pull request #2035 from sergiocampama/cpp
a2e7364 Added convenient script for generating changelog draft.
e25c56a Merge pull request #2149 from khingblue/remove-obsoleted-project
050c014 Added new has_bits.h file to cmake/extract_includes.bat.in (#2152)
f81d44f Fixed quadratic behavior in JSPB deserialization of repeated fields (#2117) (#2146)
741aa87 Remove obsoleted project of j2me
b9bc990 Fix bugs for csharp and ruby for internal integration.
c8b9d41 Fix python bugs for internal integration.
1af7c4c Fixes static analyzer issues from xcode.
08e9f70 Bump library veriosn to 3.1
22d7248 Fix bugs for internal integration.
4f379f8 Merge pull request #2144 from abscondment/fix-jruby-hash
6cb6bd9 Fix gson dependency. gson 2.3 has internal bug that it doesn't work with some versions of maven.
ebcda12 Bump version number to 3.1.0-alpha-1.
679381f Fix for maps_test.js in JavaScript. (#2145)
05aa0df Fix hash computation for JRuby's RubyMessage
a2c6501 Fix bugs for internal integration.
0dca5a5 Use a custom dictionary to avoid NSNumber operations.
96c469d Remove the custom key functions and just use the system provided defaults.
98835fb Integrate internal changes
7b00595 Merge pull request #2137 from thomasvl/objc_extensions_tweak
6ab51a0 Use a custom dictionary to avoid NSNumber operations.
5904279 Remove the custom key functions and just use the system provided defaults.
b5bbdb0 Merge pull request #2037 from abscondment/fix-2036-ruby-hash
c44ca26 Merge pull request #2130 from kilink/substring-comment-fix
9ac84f8 Fix erroneous comment regarding String.substring
3b001ca Some php engine implementation doesn't have return_value_ptr properly set. Explicitly use &return_value.
c6fa9c7 Auto-generate proto files for tests.
f174d36 Add back missing test proto files.
37e0e1f Merge pull request #2111 from pherl/3.0.x
9c4be5f Merge pull request #2112 from pherl/merge
b4235ac Merge pull request #2123 from thomasvl/objc_better_versioning_take2
1aa6500 Update the ObjC version checks to support a min and current version.
e0e5466 Check in php implementation. (#2052)
683412b Update generated files.
58860c0 Merge remote-tracking branch 'origin/3.0.x' into merge
13d6d17 Fix the version number for 3.0.2
86fcd87 Merge pull request #1765 from mbarbon/master
1affbd8 Merge pull request #2021 from zlim/bench-fix
4f032cd Merge pull request #2100 from vladmos/patch-1
22e7fa6 Merge pull request #2092 from dprotaso/master
5caf516 Resolved a conflict
78aee1b Merge pull request #2044 from wychen/Win32ANSI
643a02b Merge pull request #1636 from yugui/feature/generic-plugin
53387e5 Merge pull request #2090 from guoxiao/find
e90292b Merge pull request #2103 from adrianludwin/fix-gtest
1327e6f Update repo to use google test
7377eb2 Merge pull request #1970 from thomasvl/objc_any_helpers
a86e6d8 Compatibility with the new version of Bazel.
5d35e60 Merge pull request #2094 from thomasvl/update_wkt_comments
57170b9 Merge pull request #2096 from pherl/3.0.x
5699b92 More complete nil/reset tests within a oneof
708296e Fix some constants to be correct for the message class in use.
161b937 Fix error and add note about lossy issues
14e74f6 Support the -Wassign-enum compiler flag. (#2085)
1fc416b Allow the JsonFormat.Parser to ignore unknown fields
a15df74 Merge pull request #2087 from khingblue/fix-unused-param
337ec30 Add ObjC helpers for Any WKT.
82133ba include std::find()
08b1c71 Fix #2032 unused parameter 'deterministic'
4bc1657 Merge pull request #2079 from khingblue/fix-generate-descriptor
30e55ae Merge pull request #2083 from pherl/3.0.x
7645a3d Merge pull request #1884 from hochhaus/valueWriterFn
f9fc56c Fix #2071 replacing /bin/sh with bash
1a58673 Merge pull request #2077 from pherl/3.0.x
e298ce5 Update release date in the change log
74638a2 Merge pull request #2047 from jonathon-love/master
65a595d Merge pull request #2062 from pherl/3.0.2
01d1750 Merge pull request #2061 from pherl/changelog
9b8da10 Rm check on dependency in the C# reflection API (#2051)
96a9d97 Merge pull request #2059 from chih-hung/master
7c3f7c6 Fix #1955 clang-tidy warning misc-macro-parentheses
6e11540 Bump version number to 3.0.2
0c9999f ruby, js and c# changes
a098e80 Merge pull request #1862 from pherl/3.0.0-GA
4041ed4 objc change log
9befe47 Merge pull request #1978 from pherl/cp
9d30a98 Merge pull request #2026 from pherl/cpjs
fa6428e Merge pull request #2045 from mike07026/master
85c1adf Merge pull request #2053 from thomasvl/improve_root_registry_wiring
64958cd Fix to typo/oversight in python tests
a7eaf36 Rename UNICODE to protobuf_UNICODE
13a4124 Make Root's +extensionRegistry generation smarter.
d00cab0 Merge pull request #2039 from khingblue/remove-unused-vector
df6088a detect invaild JSON encoding in bytes field
5a17660 detect invaild JSON encoding in bytes field
e514f23 fix #1342 cause by ownership issues
48811b2 Fix Win32ErrorMessage on Unicode build
11d6cb5 Add test for Win32ErrorMessage
588a803 Support Unicode build on Windows
b964976 Merge pull request #2024 from pstavirs/master
52e491b Use 64-bit protoc binaries in compatibility tests.
8ee6f56 Remove unused vector
de02863 fix #2036: use `rb_hash_*` to accumulate hashes
047419a failing test for #2036:
c0a6a6b Merge pull request #2033 from frett/osgiExport
b6dec9b update the OSGi SymbolicName and ExportedPackage for the javanano library
dd45c0b Merge pull request #2012 from haberman/rubymapgcfix
8c93606 Merge pull request #2031 from thomasvl/dont_require_filegenerators
78a6d31 Speed up ObjC Generation with large dependency trees
e721ce6 Merge pull request #2012 from haberman/rubymapgcfix
8335b7d Fix missing import of jspb.Map (#1885)
3a674ff upb bugfix: JSON map entry keys were passing the wrong closure.
eedc7be Restore New*Callback into google::protobuf namespace since these are used by the service stubs code
7e62773 Merge pull request #1920 from gegles/master
c32b9dd Merge pull request #2018 from thomasvl/support_generate_all
f5c7a48 benchmarks: update readme.txt
4fd4471 Merge pull request #2014 from pherl/fixgmock
2e66a61 Support GenerateAll().
1760feb Update gmock links.
1e6dc7d Update links in appveyor.yml
d4213d8 Ruby: make sure map parsing frames are GC-rooted.
3d9d1a1 Merge pull request #2013 from xfxyjwf/gmock
c4a84ab Update links in appveyor.yml
bba446b Update gmock links.
08951c3 Merge pull request #2011 from tomas-abrahamsson/patch-1
4d04fcd Add an Erlang project, gpb, to third_party.md
b97a4a5 Merge pull request #2001 from nicolasnoble/patch-1
866d3e5 Fixing regular expression...
569d5ce Merge pull request #1997 from thomasvl/move_include_package_into_helpers
290d26b Remove the compiler options from ImportWriter.
93362a5 Move the ImportWriter into the ObjC Helpers.
80f65d2 Add note about JSON tests maybe being wrong. (#1992)
b5794ed Merge pull request #1984 from thomasvl/more_json_tests
7437774 More JSON tests
ff2a660 Adds better support for protos without packages  (#1979)
8b30145 Add a jenkins test status badge.
45d04d0 Merge pull request #1977 from thomasvl/bump_cocoapod_spec
584917f Bump the version in prep for the 3.0.2 tag being cut
564c02f Merge pull request #1975 from pherl/cp
a877fdf Record zero for "has" for proto3 if in a oneof.
116596a Never use strlen on utf8 runs so null characters work.
62f2ff8 Fixes extra whitespace on generated comments. (#1950)
a989501 Adds support for appledoc in generated code.  (#1928)
42ab9b4 Migrating documentation of the ObjectiveC runtime code to appledoc. (#1867)
549dde1 Merge pull request #1967 from sergiocampama/cast
e505098 Adding casts so that code importing protobug using -Wconversion does not generate warnings.
e389165 Add more JSON tests around underscores (#1963)
4763e64 Merge pull request #1957 from xfxyjwf/jenkins_badge
d9ccf4d Merge pull request #1964 from thomasvl/missing_ignores
8156410 Fix up ignores and conformance generation
336ee28 Merge pull request #1960 from jskeet/oneof
f9d93f3 Regenerate conformance files to include extra oneof fields.
bbeb983 Need to expose generated protobuf C++ headers so they can actually be accessed from other libraries.
f8c37b9 Add a jenkins test status badge.
a248420 Fixes extra whitespace on generated comments. (#1950)
cd561dd Merge pull request #1949 from thomasvl/objc_more_reset_tests
ff85a17 More complete nil/reset tests within a oneof
a0df678 Fix some constants to be correct for the message class in use.
17d601a More explicit tests for nil behaviors on fields.
91b6d04 Merge pull request #1942 from thomasvl/objc_fix_oneof_zeros
27c8962 Add more types to the zero oneof cases.
ca5b775 Record zero for "has" for proto3 if in a oneof.
ac3df39 Add conformance test for zero fields in oneofs. (#1939)
30bbbe9 Merge pull request #1934 from thomasvl/objc_strings_with_null
1a6c1d0 Never use strlen on utf8 runs so null characters work.
237f321 Adds support for appledoc in generated code.  (#1928)
56b8f44 Merge pull request #1842 from udnaan/master
32fadc0 Migrating documentation of the ObjectiveC runtime code to appledoc. (#1867)
1102a8a Merge pull request #1923 from bryongloden/patch-1
a375e1a close opened file descriptors properly
e30b7b4 Merge pull request #1924 from PiotrSikora/export_license
f1f30b5 Merge pull request #1926 from hotpxl/master
ddf6d1e [master] Add dependency cl. Fixes google/protobuf#295.
faea19c Bazel: export LICENSE file.
c59473d Merge pull request #1044 from mark-whiting/master
6d134ea Merge pull request #1898 from sergiocampama/watchos
ea081fe Fix missing import of jspb.Map (#1885)
0dca3cc Merge pull request #1865 from podsvirov/topic-cmake-project
dedd8ae Merge pull request #1914 from adamatan/typo-fix
3886860 Typo: beffer -> buffer
cf42b60 Merge pull request #1905 from pherl/fixdoc
eefd1fd CMake: Auto find ZLIB from package config if nedded
3916a0a Add and fix C++ runtime docs
8d8115b Merge pull request #1878 from haberman/rubywkt
e0779d5 Merge pull request #1903 from xfxyjwf/compatibility_tests
3cec2ea Ruby: added custom Struct exception type and fixed Makefile.am.
30647ca Use 64-bit protoc binaries in compatibility tests.
ff46627 Merge pull request #1902 from podsvirov/topic-cmake-extract-includes
7d275ec CMake: remove repeated_field_reflection.h from extract list
00d5a7f Amend the conformance tests to only use Int64/Uint64 non-wrapped values which (#1164)
275db04 Adds watch os deployment target for protobuf
6b3d120 Merge pull request #1887 from sheffatguidance/fix-js-api-documentation
1112989 Merge pull request #1884 from hochhaus/valueWriterFn
915d79e Merge pull request #1895 from google/3.0.0-GA
3ef0756 Merge pull request #1894 from pherl/fixdist
e139117 Add python/setup.cfg into dist files
169d0ca Merge pull request #1893 from google/3.0.0-GA
c479042 Merge pull request #1892 from xfxyjwf/compatibility_tests
baa4023 Run Java compatibility tests on Travis.
f3449e5 Merge pull request #1891 from pherl/python
811674f add setup.cfg for building wheels
42e5487 Merge pull request #1882 from legrosbuffle/fix-check
7e93458 Merge pull request #1888 from pherl/fixbuildzip
6a59ac9 Fix the build-zip.sh to add .exe for win packages.
9a11ab4 Fix Issue #1869: faulty js API documentation
a217408 Fix valueWriterFn variable name
c466f4b Be consistent with the use of CHECK()/ GOOGLE_CHECK().
a207a2b Fix for JRuby (assert_true is not present).
e3094a8 Ruby: added API support for well-known types.
de30c56 Merge pull request #1874 from pherl/buildzip
e3fac65 Change the build.zip.sh to support lite
2662fd3 Merge pull request #1871 from pherl/fixwin
1b1a8f4 Fix build protoc script for windows
33d2b2a CMake: Bugfix for protobuf_MODULE_COMPATIBLE
38c5f2f CMake: Link to ZLIB only if protobuf_WITH_ZLIB enabled
e8ae137 Merge pull request #1864 from pherl/galogs
e7982e4 Fixed Makefile.am for Ruby file rename.
e0d817e Change log for 3.0 GA release.
4e169bf Bring C#'s ToPascalCase method in line with C++. (This still doesn't fix the conformance tests, but at least we're now consistent with the C++ code.)
86535a1 Remove legacy_enum_values flag for GA.
be78976 Merge pull request #1861 from jskeet/fix_to_camel_case
af2fa05 Merge pull request #1859 from jskeet/remove-flag
a8aae89 Bring C#'s ToPascalCase method in line with C++. (This still doesn't fix the conformance tests, but at least we're now consistent with the C++ code.)
e672047 Remove legacy_enum_values flag for GA.
7ba044a Merge pull request #1853 from pherl/3.0.0-GA
7c9c314 fix comments.
0750797 Merge remote-tracking branch 'origin/3.0.0-GA' into 3.0.0-GA
54feb9a Fix the script comments.
b1aac0b Make protoc-artifacts able to build plugin.
032fb91 Merge branch 'master' of github.com:google/protobuf into 3.0.0-GA
154e278 fixed cmake config files install path
b6b521b Merge pull request #1851 from xfxyjwf/cint
12581b4 Fixes traivs cpp build.
234ec01 Merge pull request #1847 from haberman/GAfixes
43b36dd Fixed Makefile.am for Ruby file rename.
f11a4f1 Merge pull request #1841 from pherl/3.0.0-GA
b3b07cd Merge branch 'master' into 3.0.0-GA
ba52f2b Merge pull request #1788 from google/rubypackagecap
c43f718 Merge pull request #1846 from xfxyjwf/zip
97e2026 Added new file to ruby_EXTRA_DIST.
6d92233 Added unit test for PascalCasing package names in Ruby.
6cab568 Ruby: translate package names from snake_case -> PascalCase.
b553b87 Add a script to build protoc zip packages.
b1cecb6 Merge pull request #1837 from haberman/rubygencodename
0973822 remove extra zeros.
5a6c921 Make jruby still depend on beta-4
a17367f Define intX as standard exact-width integer types.
fb7a7c5 Bump version number for GA
4f19797 Ruby: generated foo.proto -> foo_pb.rb instead of foo.rb.
868ea59 Merge pull request #1831 from xfxyjwf/protoc
b6cd9dd Merge pull request #1834 from sergiocampama/framework
44bd6bd Merge pull request #1821 from haberman/rubyfreezestr
d07a996 Ruby: fixed string freezing for JRuby.
9e3c98f Fix maven path.
3a1259c Correctly sets the generate_for_named_framework option after parsing.
0622030 Merge pull request #1830 from xfxyjwf/travis
1b3796c Merge pull request #1829 from xfxyjwf/fixcpp
fdd970e Fix maven links.
9702b9f Keep cpp_distcheck on travis for now.
c2ced9a Remove linux tests from travis.
9009662 Fix sign-comparison warnings in public header files.
16adea3 Add a test to catch sign-comparison warnings.
4ddaad4 Merge pull request #1825 from xfxyjwf/jenkins2
de5236d Merge pull request #1828 from sergiocampama/framework
2ff9349 Fixes the parsing of the proto-framework map file.
20fbb35 Add more tests to jenkins.
2ba058c Merge pull request #1822 from xfxyjwf/java6
ff7f68a Ruby: encode and freeze strings when the are assigned or decoded.
ad49ed7 Update travis tests for Java.
30d8416 Merge pull request #1811 from xfxyjwf/fixdist
a4f68b1 Add missing files in EXTRA_DIST and add a test.
af8732e Merge pull request #1810 from xfxyjwf/versioning
e465f26 Merge pull request #1812 from jskeet/fix-travis
dd3d9d6 Merge pull request #1447 from seishun/defaults
73e0b49 fix debug.dump
deaea21 Use the dotnet-release package feed for Travis.
60cb094 Add files missing from "make dist".
36adb40 Update compatibility tests as well.
2e30301 Versioning Java GeneratedMessage.
e4b129f restore old behavior for toObject
db1b2a0 nits
970a4fd Make implicit defaults consistent with explicit defaults
77b08af Merge pull request #1802 from haberman/jsmapbin
e0e7377 Fix goog.require()/goog.provide() ordering.
24ac9c0 Merge pull request #1803 from xfxyjwf/javadoc
fa52702 Include javadoc/source in Java release packages.
7429b91 JavaScript: move extension binary info to separate struct.
2078f61 Merge remote-tracking branch 'origin/3.0.0-beta-4'
923eae8 JavaScript maps: move binary callbacks out of constructor.
56855f6 Merge pull request #1792 from xfxyjwf/changelog
82b43d1 Remove Java deterministic API.
b6a620d Merge pull request #1801 from thomasvl/oneof_framework_build_issues
2e98ed5 Use public methods to fetch oneofs in generated code.
3d9726f Mention Java lite in the changelog.
b99577c Exposes the currently registered extensions for a message and removes the internal sortedExtensionsInUse
f6d1d1a Uses head version of rvm to avoid shell_update_session not found error (#1791)
1349fb8 Added 3.0.0-beta-4 changelog.
3a8d8ea Merge pull request #1787 from xfxyjwf/steppingstone
1bce70d Fix compatiblity issues.
0b68255 Add missing golden test file.
e1f146b Merge pull request #1785 from jskeet/merge-csharp
b5ce525 Move to dotnet cli for building, and .NET Core (netstandard1.0) as target platform (#1727)
5e0de1e Remove the overload for Add(RepeatedField<T>)
2ee1e52 Optimize AddRange for sequences implementing ICollection
b053b92 Implement RepeatedField.AddRange.
d9334ea Improve exception throwing implementation in collections
10a8fb4 Move to dotnet cli for building, and .NET Core (netstandard1.0) as target platform (#1727)
4e0d051 Merge pull request #1781 from xfxyjwf/update_version
c2ebdec Update version number in AssemblyInfo.cs.
8b659b2 Merge pull request #1783 from xfxyjwf/fixlite
047a3b4 Exclude Java lite module from parent pom.xml
dd37b99 Comment out lite conformance test.
932f94e Update version number to 3.0.0-beta-4
06a0248 Add missing LIBPROTOBUF_EXPORT
7a7913e Add missing LIBPROTOBUF_EXPORT.
443eb27 Update generated files.
9086d96 Integrate from internal code base.
042993b Implement RepeatedField.AddRange (#1733)
8eb90e3 Merge pull request #1778 from yeswalrus/fix-prerelease-version
5520447 Fix a bad variable dereference causing <package>_FIND_VERSION_PRERELEASE to be ignored.
70c1ac7 Merge pull request #1776 from thomasvl/fix_dist
0d079bc Remove the baseline files from the make dist file list.
790e6af Fixed out-of-date documentation for CodedInputStream.ReadEnum. (#1581)
3560cc9 Merge pull request #1702 from lukebakken/csharp-nuget-doc-update
297ec74 Add https://metacpan.org/pod/Google::ProtocolBuffers::Dynamic
8779cba Merge pull request #1764 from jskeet/remove-is-value-type
3df146e Remove unnecessary reflection call
c404c2a Merge pull request #1762 from thomasvl/drop_perf_profiles
8c23655 Drop the performace baselines.
8b00675 Merge pull request #1757 from thomasvl/avoid_importing_src
03d9e09 Merge pull request #1735 from jskeet/attribute-placement
c850ebc Merge pull request #1758 from dago/pathmax2
e9a7fc8 Remove WriteGeneratedTypeAttributes which is a no-op
57638d5 Make sure also Solaris x86 gets PATH_MAX
eaf3451 Merge pull request #1753 from xfxyjwf/fixup
be0d7f6 Don't #import the .m files.
0d5091e Merge pull request #1742 from ottok/fix-spelling
d84d0ca Fix data member declaration order.
a29a9c5 Don't support global ::string in stringpiece.h
c10938a Merge pull request #1752 from acozzette/fix-js-tests
c64d86e Fixed failing JS tests
ec45897 Merge pull request #1712 from dkharrat/swift-error-handling
523bfd4 add nullable qualifier to nil return types
c534845 Changes to generated code from previous commit
ada0a81 Move DebuggerNonUserCodeAttribute to function members
d2ae496 Fix spelling error in function ParseTime parameter
3808d09 Fix spelling in strings and comments
cae3b0c Merge pull request #1704 from lizan/json_parse_options
02b55d2 Merge pull request #1738 from xfxyjwf/fixbuild
e102db1 Fix some failing travis tests.
aeff638 Merge pull request #1710 from chezRong/master
7e8c893 Merge pull request #1723 from thomasvl/objc_test_coverage
454dbf1 added minified JSON formatting functionality with test
2fe0556 Fix windows build.
69cc213 Updated failure_list_java.txt to remove tests that now pass
b83af52 Fixed string formatting in text_format.py to be Python2.6-compatible
d64a2d9 Integrated internal changes from Google
6cfc19e Xcode project cleanup/setup.
c18aa77 Validate the tag numbers when parsing. (#1725)
e0016c5 Merge pull request #1720 from thomasvl/issue_1716
31999a3 Add JsonParseOptions to ignore unknown fields
dc0aeaa Adding conditional compiler symbol to support .NET 3.5 (#1713)
fc4c617 Fix GPBGetMessage{Repeated,Map}Field()
7b5648c Merge pull request #1719 from esteluk/patch-1
3be6110 Fix Objective-C generator option typo
2bcd43a Merge pull request #1714 from dnkoutso/master
37ca94f Get value from text format name in GPBEnumDescriptor
0ab78e1 Merge pull request #1705 from haberman/revjsver
6a6f95d JS package.json: Added author and updated Closure Library version.
6f67be6 Merge pull request #1707 from jskeet/format-value
0421238 Expose JsonFormatter.WriteValue.
1dc6280 Moved all dependencies to devDependencies.
48735cb Add "google" to package.json "files" for WKT.
c4b40a3 Create patch release for JS to include WKT.
8069466 Modify csharp README since there are now two NuGet packages
a897ebb Merge pull request #1700 from jskeet/ordering
a230b5d Rename methods to avoid ObjC KVC collisions. (#1699)
e3f6e2b Remove ordering guarantees in the MapField documentation
1a5333b Adds destination flag to xcodebuild to avoid possible flake errors (#1697)
4f93098 Merge pull request #1666 from yeswalrus/cmake-prerelease-examples
b7560df Merge pull request #1696 from haberman/jswkt
8c20e55 Add new generation option for using proto sources from other frameworks.
104723f Fix tests for CommonJS.
98bd6d7 Merge pull request #1692 from vjpai/friendless
4308cc4 Added plugin.proto to well-known types for JS.
6daf3d2 Address review comments on function name
0e27112 Bugfix: base the require logic on the file being required.
1337486 JS: import well-known types from google-protobuf package.
37eaae2 Remove a friend-class template that is only used for the constructor, and instead create an _internal_only getter that gets the needed information. This is a workaround for a deficiency in gcc-4.4 that does not properly support templated friend classes.
52598c6 Merge pull request #1658 from yeswalrus/cmake-fixup-module
a5e116a Merge pull request #1665 from yeswalrus/cmake-package-requirements
f180ef6 Merge pull request #1683 from thomasvl/third_party_framework
a2a3399 Add support for generation sources into a framework.
f0c1492 Add the CocoaPods integration tests to Travis.
71f4a9c Fixes Xcode 8 analyzer warning saying that it was missing a release in dealloc (#1678)
088c5c4 Merge pull request #1664 from bshaffer/patch-1
4150a91 make protobuf_MSVC_STATIC_RUNTIME a dependent option to reflect it's use.
78b3498 Save the relevant options used to create a package, allow users to reject packages based on them.
5ebcfc1 Fix prerelease version matching to be more consistent with the find_package arguments.
f8a969d proper codeblock in README
fba7976 Merge pull request #879 from mathstuf/support-equals-in-proto-path
cadfbc8 Removed handling for ALIASED targets since they are unused.
401e07d Add GOOGLE_ prefix before PROTOBUF_DEPRECATED_ATTR
b60e615 Fix the undefined behavior for opensource users.
6aa981f Merge pull request #1624 from yeswalrus/cmake-prerelease-versioning
dfe0c9a Merge pull request #1643 from yeswalrus/cmake-examples
ed1d560 Merge pull request #1541 from haberman/conformancestrict
350453f Make surrogate regex even more lenient.
923d2c7 JSON surrogates Python: adjust regex for OSX error message.
23fef56 Replace handwritten protobuf-targets with exported version.
09f6a5c Use ExternalProject_Add to build the examples in a stand-alone fashion.
7155629 CMake project updates
6a61894 Added test for surrogates (valid and invalid).
84a1b60 Added update_failure_list.py.
4833b4c Surrogate checking is unpredictable, so always manually check.
bd98eae Fixed Python by updating failure lists and fixed a few broken tests.
ef7894e Make conformance tests more strict about the failure list.
20b5325 Integrate interanl changes
e34c091 Improving the granularity parsing errors (#1623)
0ab7a7f Merge pull request #1640 from os72/master
5977fb0 Generalize plugin support in Bazel Skylark rule
f6be0d1 Add https://github.com/os72/protobuf-dynamic
0420eab For prerelease versions, require protobuf_FIND_VERSION to be set.
f1091ab Include the prerelease version in the protobuf_VERSION
18a9140 Merge pull request #1625 from yeswalrus/note-versions
cc30be1 Merge pull request #1613 from yeswalrus/cmake-min-version
c461193 Merge pull request #1629 from zhongfq/patch-1
a315bb8 Merge pull request #1614 from yeswalrus/cmake-cleanup
e215828 Merge pull request #1630 from google/beta-3
e845187 Merge pull request #1620 from sergiocampama/cleanup1
4629659 add protobuf as3 lib and code generator for as3
457a297 Remove __PROTOBUF_PACKAGE_PREFIX
61c9696 Update the list of places where the version is stored.
a714c40 Removing unused GPBExceptionMessageKey
40ff94e Merge pull request #1617 from thomasvl/more_warnings
86e8f1f Merge pull request #1604 from jonwallg/repeated_types
38b9e74 Add -Woverriding-method-mismatch.
d13b3d0 remove useless cleanup - config.cmake files are executed in their own context.
c57c6ea Bump to the *real* minimum required version. Setting CMP0022 breaks CMake versions < 2.8.12
04265e4 Remove if(TRUE)
e72805e fix expected class checking in GPBSetMessageRepeatedField
0f27cab Merge pull request #1600 from thomasvl/objc_tighter_warnings
ed87c1f Merge pull request #1586 from davidzchen/python
02cd45c Bazel build: Keep generated sources and Python runtime in the same directory.
c8a440d Add more warnings to for the ObjC runtime build
d089f04 Merge pull request #1595 from thomasvl/objc_travis_tweaks
368a2f4 Automated testing tweaks for ObjC
5d0c2ee Merge pull request #1593 from thomasvl/framework_includes
173daf1 Merge pull request #1589 from hochhaus/master
7da023b Better support for using the proto library from a framework.
2131b2d Merge pull request #1588 from jeffmvr/master
7336092 Add js/binary/encoder.js to js_EXTRA_DIST.
733ef98 added missing closing bracket for _cmakedir_desc in cmake/install.cmake line 88
594ce56 Merge pull request #1578 from wal-rus/cmake-install-namespace
28f35b4 add protobuf:: namespace to installed targets
38e4713 Merge pull request #1523 from xfxyjwf/compatibility_tests
a31d14b Describe platform requirements for the compatibility tests.
5c6518f Merge pull request #1583 from thomasvl/pods_integration_followup
2338e03 Merge pull request #1576 from wal-rus/cmake-versionfile
beca1f5 Merge pull request #1575 from wal-rus/cmake-install-msvc
6c47faa Make the CocoaPods integration tests more robust
02a28a8 Update protobuf-config-version.cmake.in to correctly set the required variables (PACKAGE_VERSION_EXACT, PACKAGE_VERSION_COMPATIBLE, PACKAGE_VERSION_UNSUITABLE)
7d79458 Fix the cmake configuration file install path to be more standards compliant (See the description of cmake's config search behavior on https://cmake.org/cmake/help/v3.4/command/find_package.html)
c034ba7 Merge pull request #1574 from thomasvl/test_schemes
20b5bf6 Add shared schemes for the CocoaPods integration tests
12dffd9 Merge pull request #1572 from thomasvl/podspec_tests_2
16dd477 CocoaPod Integration Tests
cc5296b Merge pull request #1558 from haberman/rubyoneof
daec44f Expand the OS X/Xcode gitignores
2d514ce Fixed oneof behavior for enums and fixed JRuby.
b8ded18 Merge pull request #1561 from pherl/beta-3
d550528 Bump objc podspec version number
431ba4b Merge pull request #1549 from xyzzyz/arena_export
ba696e7 Merge pull request #1547 from xyzzyz/js_generator
cbb9183 Merge pull request #1559 from google/beta-3
545527e Ruby oneofs: return default instead of nil for unset fields.
32e3d7a Merge pull request #1412 from google/internal
6673283 Integrate interanl changes
718eb75 Merge pull request #1548 from anandolee/master
97aa8a0 Merge pull request #1551 from pherl/beta-3
fe06eb6 Fix protoc artifact pom version
b01b1a8 JSON format for Any message must print @type first, use OrderedDict instead of {}
4f630a6 Add compatiblity tests against v2.5.0
810ba9b Export class Arena to shared library.
f2885f6 Fix #include in js_generator.cc
67d2d45 Merge pull request #1546 from pherl/beta-3
b3bb46c Added download_url to be able to upload to pypi.
c8be6ee Merge pull request #1542 from google/beta-3
3470b68 Merge pull request #1540 from pherl/changelog
cf1fd7e Merge pull request #1533 from pherl/mapcomment
0ec34bf Update changes for lite
5e7c4cb Remove the comments about iterator validation
f2db1e0 Merge pull request #1532 from pherl/changelog
034867f Update changelogs for C++ maps
dc49706 Merge pull request #1529 from gkraynov/test-redundant-varint
5c29835 Merge pull request #1528 from pherl/master
b126706 Merge pull request #1527 from haberman/changelog
d346f49 Added release notes for Ruby and JavaScript.
ce7e502 Remove the instructions for pbconfig.h
7b87f77 Merge pull request #1521 from zhangkun83/master
04757db Fix the server id in example
9f84114 Merge pull request #1520 from pherl/hashmapvs2008
325cc42 Merge pull request #1522 from xfxyjwf/compatibility_notice
f9fd450 Merge pull request #1524 from anandolee/master
5d54a85 Test redundant varint fields decoding in JS.
371d341 Merge pull request #1518 from jskeet/move_test
e4ca694 python changes
09732c9 Add compatibility notice for Java.
28cb77f Fine-tune build scripts and better documentation.
e1f588a Merge pull request #1 from google/beta-3
71dd9c4 Merge pull request #1515 from pherl/changelog-beta3
ede9cc4 Update comments for csharp, zero-copy and objc.
19472bf Merge pull request #1512 from pherl/beta-3
017d390 Fix csharp version
dbdf6d9 Bridge vs2008 hashmaps.
5668e2e Fix typo.
920ee73 Merge pull request #1483 from wal-rus/fix-boost-incompatibility
7cc9cb4 Move test for standalone BoolValue to JsonParserTest
cca2d44 Merge pull request #1517 from jhickson/boolvalue
835fb94 Fixed parsing of BoolValue.
2b22b61 Merge remote-tracking branch 'refs/remotes/google/master'
c67879b Merge pull request #1514 from pherl/fix_heap_check
0e4d1ea Initial draft for changelog.
e8737d8 Fix the command line interface unittest again
cdd3ec7 Merge pull request #1513 from pherl/fix-build-protoc
25dd690 Fix protoc build artifact script.
5dea201 Update version numbers for other languages
dbed8a0 Update version numbers for beta3
a1938b2 Merge pull request #1510 from thomasvl/nonnull
4755bdc Declare an init and avoid passing NULL to initWithValue:count:
4c6259b Merge pull request #1498 from thomasvl/build_cleanup
f4bc9e0 Remove confounding and unused #define - breaks boost/predef/other/endian.h
d392ed4 Merge pull request #1502 from pherl/master
ce6bec7 Remove accidentally restored deleted files.
9d0f560 Merge pull request #1494 from pherl/master
76a96d4 Merge pull request #1499 from beardedN5rd/master
2eb774e after comment of Feng Xiao changed the entry to g++
ace2690 Merge pull request #1496 from ozkuran/master
b661fb5 Add the missing maintiner-clean entry for benchmarks
ce2ef0d Properly express all outputs for the conformance build
f367642 Add two missing ignores for conformance directory.
b12f630 updated README
9b3357d Updated README.md
5b5e369 Merge pull request #1471 from jskeet/any-host
f8a5c5f Fix using std::shared_ptr
75e5898 Fix the std::string error introduced in integration.
17b6fc3 Merge pull request #1409 from eeight/fix_enum_corruption
72e162c Merge pull request #1482 from nicolasnoble/rake-tweaks-2
edd2949 Properly generating well known proto files for the macos build.
07bcf21 Merge pull request #1464 from google/benchmarks
7dda312 Merge pull request #1473 from nicolasnoble/rake-tweaks
247ef1f Addressed PR comments.
09f1757 Merge pull request #1467 from pherl/master
236b939 Addressing concerns.
e0df23a Update descritpor protos for objc
aed7b34 Merge pull request #1474 from pherl/fixscript
454d5be Merge the script fix.
cf7e99d Fix cp -r usage to be portable.
1f8b6da Few tweaks to the rakefile to permit native gems compilation with the proto files generation.
b2d4b1a Fixed for pre-C++11 ifstream which does not accept std::string.
49a8918 Read files directly from filesystem since xxd isn't always available.
cb36bde Make the C++ tests build the benchmarking code.
1ce5bd8 Updates for PR comments.
61307b8 Allow custom type URL prefixes in Any.Pack
f86d39c Update file lists.
12fdeb9 Merge branch 'master' of github.com:google/protobuf
cf14183 Down integrate from Google internal.
b53417c Merge pull request #1462 from acozzette/ruby-2.3
30a2f70 Added README describing the directory.
2e83110 Added framework for generating/consuming benchmarking data sets.
cbb6b28 Merge pull request #1461 from thomasvl/fix_bool_handing
3064628 Fix up -hash/-isEqual: for bool storage.
bbb68fe Added dig and bsearch_index to RepeatedField methods forwarded to array
f53f911 Merge pull request #1455 from haberman/updateupb
66f0745 Merge pull request #1454 from thomasvl/enum_defaults
18b6a32 Proper checking of enum with non zero default
d419ca1 Updated upb and simplified ruby code a bit with new upb method.
4057447 Merge pull request #1444 from mbrtargeting/master
385755e Add initial design document for Swift protocol buffers. (#1442)
db93833 Added serialVersionUID to ExtendableMessage.
034294b Merge pull request #1438 from xfxyjwf/docs
f4f9aec Fix bug with silent message corruption in LITE_RUNTIME.
0ad2048 Merge pull request #1416 from cwhipkey/master
8052dc7 Add a docs directory and move the third-party add-ons page here.
462e7fa protoc: support '=' in --proto_path arguments
f00300d Merge pull request #1414 from xyzzyz/googletest
1ccb4ca Merge pull request #1434 from jskeet/regenerate
c588ac4 Regenerate well-known types for C#
e539e98 Merge pull request #1433 from thomasvl/check_wkt
511f28b ObjC support for failing the build in the generated WKTs are out of date
f265fb8 Merge pull request #1401 from jskeet/enum-casing
36978c3 Merge pull request #1417 from seishun/windows2
d90d615 Attempt to fix AppVeyor build by exporting GetEnumValueName
790f4c8 Use the original name in JSON formatting.
84ea2c7 Regenerate all C# code and make it compile
75626ed Add C# codegen changes to enum value names (mostly C++)
1dc8194 Merge pull request #1428 from pherl/master
1b0ff34 Add missing includes in field mask test
52825bf Merge pull request #1426 from thomasvl/fix_comment_typo
e664aa6 Regenerate the WKT to pick up current changes to the proto files.
83a7a5e Merge pull request #1402 from davidzchen/py2and3
3633bcd Fix comment typo
072296f Merge pull request #1422 from pherl/master
1f4f3e2 Update file list to include the missing extension lite file.
7ff229f Support Windows in gulpfile.js
ca9bbd7 Merge pull request #1413 from haberman/updateupb
baf52bd Change protobuf CPP proto generator to support the 'lite' option in proto3.
e67ef3d Bugfix for JSON error case.
800e986 Remove no longer applicable documentation from README.md.
194ad62 Ruby JSON: always accept both camelCase and original field names.
1b912fc Remove googletest.h header from stringprintf.cc
90c7f6e Documented the JSON change and compatibility flags.
94e54b3 Updated upb: picked up legacy JSON flags to help Ruby users migrate.
814685c Merge pull request #1397 from google/internal-merge
3c4ce52 Fix for gulpfile.js.
2a197b3 Use 0 as the default value for all enums, rather than finding the actual enum value name
3ffbdd7 Merge pull request #1400 from jskeet/fix-internal
5ebeefb Add missing PY2AND3 srcs_versions attributes to Python Bazel build targets.
0a902ee Fix to csharp_options - initialize internal_access to false.
2cd79bf Removed duplicated operator delete from merge conflict.
4465daa Merge branch 'master' into internal-merge
667f4a6 Merge pull request #1393 from gvaish/master
1523936 Fix for CommonJS tests.
09292d5 Merge pull request #1392 from anandolee/master
a6e3931 Added support for internal_access for C#
cef46e1 Merge pull request #1390 from jskeet/tidy-up
c612074 sync the Manually integrate changes in google3/third_party
28c5c25 Merge pull request #1391 from thomasvl/string_tweaks
f98d2f5 Updating Xcode Settings to use iOS 9.3
2a18bb5 Add more documentation for csharp_options.h
bfd1c84 Line-wrapping changes only for C# generator code
c9167f2 Error during parsing for invalid UTF-8 instead of dropping dropping data.
f3f5b3f Add tests to ensure we read strings with BOMs so we don't forget about lessons of the past.
89719f0 Merge pull request #1349 from gvaish/master
f3fe75b Merge pull request #1386 from andrewharp/patch-2
74d8b0b Added access_level for types
3b4e7dc Update BUILD
b56b461 Do not link in pthread library for Android builds.
a771c9e Merge pull request #852 from qzix/master
268ce28 Added deprecated option handling for objective-c generator
aeacf51 Merge pull request #1381 from pherl/internal-merge
7630a83 Merge branch 'master' into internal-merge
cba75ad Merge branch 'master' of github.com:google/protobuf
89343d8 Do not use C++11 unicode escape in unittest.
452e2b2 Merge pull request #1353 from keveman/master
cf828de Linking the cpp implementation extension statically with libprotobuf
93811ca Do not let windows.h define min/max macros
3b6df06 Allow bigobj for map_unittest
9d7a172 Merge pull request #1377 from jskeet/remove-duplicate-tests
a293180 Merge pull request #1378 from thomasvl/manual_stream_parsing_helpers
331cee5 Add -position and -isAtEnd for use when manually parsing input streams.
46e088e Remove duplicate test cases.
099ff1e Merge pull request #1369 from jskeet/tools-nuspec
203bb5e Fix re-definition issue of winsock.h and winsock2.h
1bf446c Disable sign-compare warning.
7b1cbbd Fix signed-compare warning.
012ac9a revert unexpected change for py26
bc1f2e7 Fix WIN32 build for map_test.
cbfd9d4 Remove export macros for classes nested in a template class.
81eb84c Merge pull request #1371 from keveman/oversize_protos
1283625 Added an API to allow oversize protos when using C++ extension in Python
5805c2d Fix javanano package
fc7eeda Fix json_format.py in py26
5c63266 Merge pull request #1366 from xyzzyz/int128_ostream
94aa50f Fix breakage of referring to table_ in static func
9e7fa06 Temporarily disable begin is fast test.
dfd4760 Remove duplicate line
ca0461c Introduce a new nuget package, Google.Protobuf.Tools, basically to contain protoc on multiple platforms.
a16c8a5 Merge pull request #1362 from jskeet/tweak_json_name
955841e Replace #include <iostream> with #include <ostream>
0de06f5 Merge branch 'master' of github.com:google/protobuf
3b3c8ab Integrate google internal changes.
a25e996 Merge pull request #1360 from pherl/master
34d0cc2 Merge pull request #1295 from haberman/docker
71e8dca Refactoring of FieldDescriptor
261fde1 Merge pull request #1326 from the-alien/csharp_json_name
a15b916 Merge branch 'master' into docker
e164f10 Use the T() instead of NULL for the default value.
af34538 Merge branch 'master' of https://github.com/google/protobuf into csharp_json_name
6f8dd21 Code review fixes
261ee02 Merge pull request #1358 from thomasvl/travis_tweaks
8d47d78 Mark iOS tests as able to fail.
9240acd Merge pull request #1350 from thomasvl/over_release
3f91744 The message was autoreleased, the -releases are an over release.
8126912 Merge pull request #1345 from smparkes/smparkes/well-known-protos
d5a5732 export well known protos
34eeeff Merge pull request #1344 from topillar/patch-1
64dfb5f Update coded_stream.h
698fa8e Merge pull request #1335 from pradeepg26/master
9209136 Merge pull request #1339 from thomasvl/delay_dispatch_semaphore_creation
bd41a39 Only create the readonlySemaphore on demand.
4d98369 Allow custom URLs for Any in JsonFormat
cab5eae Replace ancient m4/acx_pthread.m4 with m4/ax_pthread.m4
0d32ab3 csharp: add support for the json_name option
5e93384 Merge pull request #1325 from thomasvl/shrink_overhead
79a23c4 Shrink ObjC overhead (generated size and some runtime sizes)
ca3dc15 Merge pull request #1318 from smparkes/smparkes/grpc
44fdead Merge pull request #1291 from sergiocampama/devel
9aea0ef Merge pull request #1312 from petewarden/master
a9244ca add java/util support based on java/util/pom.xml
c71f184 Merge pull request #1278 from smparkes/master
dfaf1aa Merge pull request #1317 from benvanik/patch-1
58f0764 Fixing compilation error when building with emscripten.
ea18866 pass correct args to protoc for java wellknown protos when used as an external repository
bc2d6c2 Merge remote-tracking branch 'upstream/master'
f0c1a86 Added iOS settings to Bazel build
48ebb29 Merge pull request #1299 from tatraian/master
e2fb1d9 Comment has been added to fix (issue #1266)
a8db268 Merge pull request #1309 from thomasvl/leading_special_prop_names
1bf4b38 Fix up handing of fields with leading names that should be all caps.
3dd3238 Merge pull request #1306 from silviulica/master
4573edb Update version to 3.0.0b2.post2
6a8815b Merge pull request #1304 from thomasvl/headerdocs
36650a0 HeaderDoc support in the library and generated sources
f2d3408 Merge pull request #1301 from avgweb/master
ad2d775 Replace StringBuilder with TextWriter in JsonFormatter
9242d9b Merge pull request #1298 from craigcitro/fix_setup
3cc35ad Fix compiling clang/libc++ builds. (Issue: #1266)
0e7c0c2 Add back the namespace_packages arg in setup.py.
e70f925 Merge pull request #1139 from haberman/rubyjsoncamel
67c727c Rearranged and commented files for running under Jenkins.
37663e8 Merge pull request #1292 from haberman/ruby-allow-descriptor
35227b4 Removed the generated Ruby file from Makefile.am.
7d793c1 Disable attempt to use ccache for docker build.
2bda98f Properly report C++ build time.
1ee0fda Use a local Maven repository to avoid network fetches during tests.
513875d Generate well-known types in Ruby extension and prune unneeded proto2 dependencies.
b5a35b4 Adds more information to Objective C error when the expected objc_class_prefix option is missing.
2f3f1de Make Java copy into separate directories so the tests can run concurrently.
38bc155 Added code to generate XML output file for more granular results.
ffc8118 Added Ruby 2.1, Oracle Java, and C#.
78f9b68 Upgrade Python packages using pip.
f6153b5 Work around tox bug.
b28b3f6 Configure ccache directory.
d08c39c Put Maven in batch mode to avoid spamming the logs.
483533d Install Python deps in Docker image.
0b931bc Add another test (javanano), but run it in parallel.
0f8c25d Properly add JDK deps in the Docker image.
738393b Try running multiple tests in a row.
d33e93b Added ccache support.
57be1d7 Added some initial shell scripts and docker file.
7810589 Merge pull request #1260 from legrosbuffle/master
584233b Merge pull request #1287 from jskeet/fix-typo
f222a9a Fix copy/paste typo in CodedInputStreamTest
52f62e3 Merge pull request #1274 from murgatroid99/node_relative_requires
9f775a8 Merge pull request #1286 from jskeet/idisposable
c0cf71b Implement IDisposable for CodedInputStream and CodedOutputStream
60a0d41 Merge pull request #1233 from davidzchen/python-path
985c968 Remove hack for building Python support with Bazel.
fb714b3 Merge pull request #1275 from keveman/grpc_support
f5c7363 Fixed grpc C++ plugin support.
c9f8a1b Moved CommonJS-specific files into commonjs directory
a862b6b Fix CommonJS relative require generation, and test it
cc775f7 Merge pull request #1259 from silviulica/master
fc51bdc Merge pull request #1268 from keveman/grpc_support
cb39204 Updated library generation with iOS options
f0966a7 Added grpc plugin support to cc_proto_library.
8f67b16 Merge pull request #1267 from jskeet/vs2015
513a8a6 Merge pull request #804 from bsilver8192/master
4237146 Require VS2015 in the solution file
32daf51 Merge pull request #1215 from haberman/commonjs
24c5424 Added a bit more to README.md, and allowed custom PROTOC var in tests.
894c4d6 Merge pull request #1257 from thomasvl/objc_generics
b3d802d Make cpp generated enum constants constexpr when Options::proto_h is specified.
786f80f Add a modified patch from craigcitro@ to handle namespace sharing.
c003abb Merge pull request #1240 from jskeet/validate_group
4ab9186 Merge pull request #1258 from haberman/releasenotes
81e75c1 Some fixes for the most recent release notes.
f654d49 Updated upb from latest changes.
2480acb Support ObjC Generic Collections
78da666 Changed Ruby to properly camelCase its JSON by default.
907ad4a Properly camelCase when translating to CommonJS.
29d58d3 Removed unused directives from tests that aren't run under CommonJS.
c348af2 Addressed more code review comments.
7726cd2 Integrate review comments.
5195b7f Greatly expanded README.md.
59ea500 Use "node" as binary instead of "nodejs".
35298f9 Fixed definition of extensions, and added CommonJS tests to Travis.
77af5d0 Fixed nested message scopes for CommonJS.
d6a186a Added some documentation in comments.
9e60036 Moved CommonJS-specific files to commonjs/.
e9f31ee CommonJS tests are now passing.
55cc3aa WIP.
9ab11c6 Merge pull request #1255 from thomasvl/mark_os_x_python_cpp_failing
e0dd14c List python_cpp as failing on OS X
507213b Merge pull request #1254 from thomasvl/disable_xctool_updates
8c78450 Disable the xctool updates
abc09f7 Merge pull request #1239 from jskeet/call_generate_protos
c40f8c1 Merge pull request #1229 from keveman/unlimited_binary_proto
61e8e21 Merge pull request #1241 from jskeet/more-merge-wrapper-tests
d41db75 Merge pull request #260 from ejsd1989/issue-#242
8fc045d Merge pull request #1224 from google/rubysentinel
99a3e30 Added PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS macro and setting it when --allow_oversize_protos=true is passed to bazel build. When this macro is set, SetTotalBytesLimit is called to remove the 64MB limit on binary protos when during ParseFromString.
7cf5b81 Merge pull request #1247 from thomasvl/xctool_plain_output
efca368 Move the xctool use of -reporter into a common spot and always use "plain" to get more readable logs on travis.
ee819ea Merge pull request #1245 from thomasvl/tweak_xctool_ios_run
30e645b Tweak the xctool run for iOS tests to try and sort out flake
7d1cc10 Merge pull request #1244 from thomasvl/bump_xcode_version
1324119 Bump up travis to Xcode 7.2
0262e04 Add more tests around merging wrappers
9bdc848 Validate that end-group tags match their corresponding start-group tags
957e877 Generate C# code whenever descriptor.proto changes
69ac430 Removed 'optional' from proto3 syntax file.
fd1c289 Adding missing generic gcc 64-bit atomicops.
ff156e4 Add atomics support for 32-bit PPC.
914605c Removal of null check
a1c5e45 Removal of null check

Change-Id: Id88028efe92b49fd68a02de01e4f991765798c40
git-subtree-dir: third_party/protobuf
git-subtree-split: 48cb18e5c419ddd23d9badcfe4e9df7bde1979b2
diff --git a/java/README.md b/java/README.md
index 060d9ac..5e4fb8b 100644
--- a/java/README.md
+++ b/java/README.md
@@ -1,25 +1,74 @@
-Protocol Buffers - Google's data interchange format
-===================================================
-
-[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+# Protocol Buffers - Google's data interchange format
 
 Copyright 2008 Google Inc.
 
-This directory contains the Java Protocol Buffers runtime library.
+https://developers.google.com/protocol-buffers/
 
-Installation - With Maven
-=========================
+## Use Java Protocol Buffers
 
-The Protocol Buffers build is managed using Maven.  If you would
-rather build without Maven, see below.
+To use protobuf in Java, first obtain the protocol compiler (a.k.a., protoc,
+see instructions in the toplevel [README.md](../README.md)) and use it to
+generate Java code for your .proto files:
+
+    $ protoc --java_out=${OUTPUT_DIR} path/to/your/proto/file
+
+Include the generated Java files in your project and add a dependency on the
+protobuf Java runtime. If you are using Maven, use the following:
+
+```xml
+<dependency>
+  <groupId>com.google.protobuf</groupId>
+  <artifactId>protobuf-java</artifactId>
+  <version>3.5.1</version>
+</dependency>
+```
+
+Make sure the version number of the runtime matches (or is newer than) the
+version number of the protoc.
+
+If you want to use features like protobuf JsonFormat, add a dependency on the
+protobuf-java-util package:
+
+```xml
+<dependency>
+  <groupId>com.google.protobuf</groupId>
+  <artifactId>protobuf-java-util</artifactId>
+  <version>3.5.1</version>
+</dependency>
+```
+
+### Use Java Protocol Buffers on Android
+
+For Android users, it's recommended to use protobuf Java Lite runtime because
+of its smaller code size. Java Lite runtime also works better with Proguard
+because it doesn't rely on Java reflection and is optimized to allow as much
+code stripping as possible. You can following these [instructions to use Java
+Lite runtime](lite.md).
+
+### Use Java Protocol Buffers with Bazel
+
+Bazel has native build rules to work with protobuf. For Java, you can use the
+`java_proto_library` rule for server and the `java_lite_proto_library` rule
+for Android. Check out [our build files examples](../examples/BUILD) to learn
+how to use them.
+
+## Build from Source
+
+Most users should follow the instructions above to use protobuf Java runtime.
+If you are contributing code to protobuf or want to use a protobuf version
+that hasn't been officially released yet, you can folllow the instructions
+below to build protobuf from source code.
+
+### Build from Source - With Maven
 
 1) Install Apache Maven if you don't have it:
 
      http://maven.apache.org/
 
-2) Build the C++ code, or obtain a binary distribution of protoc.  If
-   you install a binary distribution, make sure that it is the same
-   version as this package.  If in doubt, run:
+2) Build the C++ code, or obtain a binary distribution of protoc (see
+   the toplevel [README.md](../README.md)). If you install a binary
+   distribution, make sure that it is the same version as this package.
+   If in doubt, run:
 
      $ protoc --version
 
@@ -44,36 +93,20 @@
 
    The .jar will be placed in the "target" directory.
 
-Installation - 'Lite' Version - With Maven
-==========================================
+The above instructions will install 2 maven artifacts:
 
-Building the 'lite' version of the Java Protocol Buffers library is
-the same as building the full version, except that all commands are
-run using the 'lite' profile.  (see
-http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
+  * protobuf-java: The core Java Protocol Buffers library. Most users only
+                   need this artifact.
+  * protobuf-java-util: Utilities to work with protos. It contains JSON support
+                        as well as utilities to work with proto3 well-known
+                        types.
 
-E.g. to install the lite version of the jar, you would run:
-
-    $ mvn install -P lite
-
-The resulting artifact has the 'lite' classifier.  To reference it
-for dependency resolution, you would specify it as:
-
-```
-  <dependency>
-    <groupId>com.google.protobuf</groupId>
-    <artifactId>protobuf-java</artifactId>
-    <version>${version}</version>
-    <classifier>lite</classifier>
-  </dependency>
-```
-
-Installation - Without Maven
-============================
+### Build from Source - Without Maven
 
 If you would rather not install Maven to build the library, you may
 follow these instructions instead.  Note that these instructions skip
-running unit tests.
+running unit tests and only describes how to install the core protobuf
+library (without the util package).
 
 1) Build the C++ code, or obtain a binary distribution of protoc.  If
    you install a binary distribution, make sure that it is the same
@@ -86,15 +119,48 @@
 
 2) Invoke protoc to build DescriptorProtos.java:
 
-     $ protoc --java_out=src/main/java -I../src \
+     $ protoc --java_out=core/src/main/java -I../src \
          ../src/google/protobuf/descriptor.proto
 
-3) Compile the code in src/main/java using whatever means you prefer.
+3) Compile the code in core/src/main/java using whatever means you prefer.
 
 4) Install the classes wherever you prefer.
 
-Usage
-=====
+## Compatibility Notice
+
+* Protobuf minor version releases are backwards-compatible. If your code
+  can build/run against the old version, it's expected to build/run against
+  the new version as well. Both binary compatibility and source compatibility
+  are guaranteed for minor version releases if the user follows the guideline
+  described in this section.
+
+* Protobuf major version releases may also be backwards-compatbile with the
+  last release of the previous major version. See the release notice for more
+  details.
+
+* APIs marked with the @ExperimentalApi annotation are subject to change. They
+  can be modified in any way, or even removed, at any time. Don't use them if
+  compatibility is needed. If your code is a library itself (i.e. it is used on
+  the CLASSPATH of users outside your own control), you should not use
+  experimental APIs, unless you repackage them (e.g. using ProGuard).
+
+* Deprecated non-experimental APIs will be removed two years after the release
+  in which they are first deprecated. You must fix your references before this
+  time. If you don't, any manner of breakage could result (you are not
+  guaranteed a compilation error).
+
+* Protobuf message interfaces/classes are designed to be subclassed by protobuf
+  generated code only. Do not subclass these message interfaces/classes
+  yourself. We may add new methods to the message interfaces/classes which will
+  break your own subclasses.
+
+* Don't use any method/class that is marked as "used by generated code only".
+  Such methods/classes are subject to change.
+
+* Protobuf LITE runtime APIs are not stable yet. They are subject to change even
+  in minor version releases.
+
+## Documentation
 
 The complete documentation for Protocol Buffers is available via the
 web at:
diff --git a/java/compatibility_tests/README.md b/java/compatibility_tests/README.md
new file mode 100644
index 0000000..72c6034
--- /dev/null
+++ b/java/compatibility_tests/README.md
@@ -0,0 +1,50 @@
+# Protobuf Java Compatibility Tests
+
+This directory contains tests to ensure protobuf library is compatible with
+previously released versions.
+
+## Directory Layout
+
+For each released protobuf version we are testing compatibility with, there
+is a sub-directory with the following layout (take v2.5.0 as an example):
+
+  * v2.5.0
+    * test.sh
+    * pom.xml
+    * protos/ - unittest protos.
+    * more_protos/ - unittest protos that import the ones in "protos".
+    * tests/ - actual Java test classes.
+
+The testing code is extracted from regular protobuf unittests by removing:
+
+  * tests that access package private methods/classes.
+  * tests that are known to be broken by an intended behavior change (e.g., we
+    changed the parsing recursion limit from 64 to 100).
+  * all lite runtime tests.
+
+It's also divided into 3 submodule with tests depending on more_protos and
+more_protos depending on protos. This way we can test scenarios where only part
+of the dependency is upgraded to the new version.
+
+## How to Run The Tests
+
+We use a shell script to drive the test of different scenarios so the test
+will only run on unix-like environments. The script expects a few command
+line tools to be available on PATH: git, mvn, wget, grep, sed, java.
+
+Before running the tests, make sure you have already built the protoc binary
+following [the C++ installation instructions](../../src/README.md). The test
+scripts will use the built binary located at ${protobuf}/src/protoc.
+
+To start a test, simply run the test.sh script in each version directory. For
+example:
+
+    $ v2.5.0/test.sh
+
+For each version, the test script will test:
+
+  * only upgrading protos to the new version
+  * only upgrading more_protos to the new version
+
+and see whether everything builds/runs fine. Both source compatibility and
+binary compatibility will be tested.
diff --git a/java/compatibility_tests/v2.5.0/deps/pom.xml b/java/compatibility_tests/v2.5.0/deps/pom.xml
new file mode 100644
index 0000000..7ceb960
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/deps/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.google.protobuf.compatibility</groupId>
+  <artifactId>compatibility-test-deps</artifactId>
+  <version>2.5.0</version>
+
+  <name>Compatibility Test Dependencies</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+      <version>2.2.1</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.6</version>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/java/compatibility_tests/v2.5.0/more_protos/pom.xml b/java/compatibility_tests/v2.5.0/more_protos/pom.xml
new file mode 100644
index 0000000..ff0c413
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf.compatibility</groupId>
+    <artifactId>compatibility-test-suite</artifactId>
+    <version>2.5.0</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>com.google.protobuf.compatibility</groupId>
+  <artifactId>compatibility-more-protos</artifactId>
+  <version>2.5.0</version>
+
+  <name>More protos for Compatibility test</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.protobuf</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${more_protos.protobuf.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.protobuf.compatibility</groupId>
+      <artifactId>compatibility-protos</artifactId>
+      <version>2.5.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.3</version>
+        <configuration>
+          <source>1.6</source>
+          <target>1.6</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <tasks>
+                <mkdir dir="target/generated-sources" />
+                <exec executable="${more_protos.protoc.path}">
+                  <arg value="--java_out=target/generated-sources" />
+                  <arg value="--proto_path=src/proto" />
+                  <arg value="src/proto/google/protobuf/unittest.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_optimize_for.proto" />
+                  <arg value="src/proto/com/google/protobuf/multiple_files_test.proto" />
+                </exec>
+              </tasks>
+              <sourceRoot>target/generated-sources</sourceRoot>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/multiple_files_test.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 0000000..9a04014
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/multiple_files_test.proto
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+  message NestedMessage {
+    optional int32 i = 1;
+  }
+  enum NestedEnum {
+    BAZ = 3;
+  }
+  optional NestedMessage nested = 1;
+  repeated TestAllTypes foreign = 2;
+  optional NestedEnum nested_enum = 3;
+  optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+  FOO = 1;
+  BAR = 2;
+}
+
+service ServiceWithNoOuter {
+  rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+  optional int32 extension_with_outer = 1234567;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_builders_test.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_builders_test.proto
new file mode 100644
index 0000000..abffb9d
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_builders_test.proto
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jonp@google.com (Jon Perlow)
+//
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "NestedBuilders";
+
+
+message Vehicle {
+  optional Engine engine = 1;
+  repeated Wheel wheel = 2;
+}
+
+message Engine {
+  optional int32 cylinder = 1;
+  optional int32 liters = 2;
+}
+
+message Wheel {
+  optional int32 radius = 1;
+  optional int32 width = 2;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension.proto
new file mode 100644
index 0000000..9fe5d56
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension.proto
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions. Note that this must be defined in
+// a separate file to properly test the initialization of the outer class.
+
+
+import "com/google/protobuf/non_nested_extension.proto";
+
+package protobuf_unittest;
+
+message MyNestedExtension {
+  extend MessageToBeExtended {
+    optional MessageToBeExtended recursiveExtension = 2;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension_lite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension_lite.proto
new file mode 100644
index 0000000..16ee46e
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/nested_extension_lite.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions for a MessageLite messages. Note that
+// this must be defined in a separate file to properly test the initialization
+// of the outer class.
+
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+import "com/google/protobuf/non_nested_extension_lite.proto";
+
+message MyNestedExtensionLite {
+  extend MessageLiteToBeExtended {
+    optional MessageLiteToBeExtended recursiveExtensionLite = 3;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension.proto
new file mode 100644
index 0000000..f61b419
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions.
+
+
+package protobuf_unittest;
+
+message MessageToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtension {
+}
+
+extend MessageToBeExtended {
+  optional MyNonNestedExtension nonNestedExtension = 1;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto
new file mode 100644
index 0000000..3c82659
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions for a MessageLite messages.
+
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message MessageLiteToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtensionLite {
+}
+
+extend MessageLiteToBeExtended {
+  optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/test_bad_identifiers.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/test_bad_identifiers.proto
new file mode 100644
index 0000000..6e67d97
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jonp@google.com (Jon Perlow)
+
+// This file tests that various identifiers work as field and type names even
+// though the same identifiers are used internally by the java code generator.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+package io_protocol_tests;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TestBadIdentifiersProto";
+
+message TestMessage {
+}
+
+message Descriptor {
+  option no_standard_descriptor_accessor = true;
+  optional string descriptor = 1;
+  message NestedDescriptor {
+    option no_standard_descriptor_accessor = true;
+    optional string descriptor = 1;
+  }
+  optional NestedDescriptor nested_descriptor = 2;
+}
+
+message Parser {
+  enum ParserEnum {
+    PARSER = 1;
+  }
+  optional ParserEnum parser = 1;
+}
+
+message Deprecated {
+  enum TestEnum {
+    FOO = 1;
+  }
+
+  optional int32 field1 = 1 [deprecated=true];
+  optional TestEnum field2 = 2 [deprecated=true];
+  optional TestMessage field3 = 3 [deprecated=true];
+}
+
+message Override {
+  optional int32 override = 1;
+}
+
+message Object {
+  optional int32 object = 1;
+  optional string string_object = 2;
+}
+
+message String {
+  optional string string = 1;
+}
+
+message Integer {
+  optional int32 integer = 1;
+}
+
+message Long {
+  optional int32 long = 1;
+}
+
+message Float {
+  optional float float = 1;
+}
+
+message Double {
+  optional double double = 1;
+}
+
+service TestConflictingMethodNames {
+  rpc Override(TestMessage) returns (TestMessage);
+}
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/descriptor.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..a785f79
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/descriptor.proto
@@ -0,0 +1,620 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+
+package google.protobuf;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;       // file name, relative to root of source tree
+  optional string package = 2;    // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+  // Indexes of the public imported files in the dependency list above.
+  repeated int32 public_dependency = 10;
+  // Indexes of the weak imported files in the dependency list.
+  // For Google-internal migration only. Do not use.
+  repeated int32 weak_dependency = 11;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // This field contains optional information about the original source code.
+  // You may safely remove this entire field whithout harming runtime
+  // functionality of the descriptors -- the information is needed only by
+  // development tools.
+  optional SourceCodeInfo source_code_info = 9;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;
+    optional int32 end = 2;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  optional MessageOptions options = 7;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE         = 1;
+    TYPE_FLOAT          = 2;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+    // negative values are likely.
+    TYPE_INT64          = 3;
+    TYPE_UINT64         = 4;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+    // negative values are likely.
+    TYPE_INT32          = 5;
+    TYPE_FIXED64        = 6;
+    TYPE_FIXED32        = 7;
+    TYPE_BOOL           = 8;
+    TYPE_STRING         = 9;
+    TYPE_GROUP          = 10;  // Tag-delimited aggregate.
+    TYPE_MESSAGE        = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES          = 12;
+    TYPE_UINT32         = 13;
+    TYPE_ENUM           = 14;
+    TYPE_SFIXED32       = 15;
+    TYPE_SFIXED64       = 16;
+    TYPE_SINT32         = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64         = 18;  // Uses ZigZag encoding.
+  };
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL      = 1;
+    LABEL_REQUIRED      = 2;
+    LABEL_REPEATED      = 3;
+    // TODO(sanjay): Should we add LABEL_MAP?
+  };
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // If type_name is set, this need not be set.  If both this and type_name
+  // are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
+  optional Type type = 5;
+
+  // For message and enum types, this is the name of the type.  If the name
+  // starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+  // rules are used to find the type (i.e. first the nested types within this
+  // message are searched, then within the parent, on up to the root
+  // namespace).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // For numeric types, contains the original text representation of the value.
+  // For booleans, "true" or "false".
+  // For strings, contains the default text contents (not escaped in any way).
+  // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+  // TODO(kenton):  Base-64 encode?
+  optional string default_value = 7;
+
+  optional FieldOptions options = 8;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * For options which will be published and used publicly by multiple
+//   independent entities, e-mail protobuf-global-extension-registry@google.com
+//   to reserve extension numbers. Simply provide your project name (e.g.
+//   Object-C plugin) and your porject website (if available) -- there's no need
+//   to explain how you intend to use them. Usually you only need one extension
+//   number. You can declare multiple options with only one extension number by
+//   putting them in a sub-message. See the Custom Options section of the docs
+//   for examples:
+//   http://code.google.com/apis/protocolbuffers/docs/proto.html#options
+//   If this turns out to be popular, a web service will be set up
+//   to automatically assign option numbers.
+
+
+message FileOptions {
+
+  // Sets the Java package where classes generated from this .proto will be
+  // placed.  By default, the proto package is used, but this is often
+  // inappropriate because proto packages do not normally start with backwards
+  // domain names.
+  optional string java_package = 1;
+
+
+  // If set, all the classes from the .proto file are wrapped in a single
+  // outer class with the given name.  This applies to both Proto1
+  // (equivalent to the old "--one_java_file" option) and Proto2 (where
+  // a .proto always translates to a single class, but you may want to
+  // explicitly choose the class name).
+  optional string java_outer_classname = 8;
+
+  // If set true, then the Java code generator will generate a separate .java
+  // file for each top-level message, enum, and service defined in the .proto
+  // file.  Thus, these types will *not* be nested inside the outer class
+  // named by java_outer_classname.  However, the outer class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default=false];
+
+  // If set true, then the Java code generator will generate equals() and
+  // hashCode() methods for all messages defined in the .proto file. This is
+  // purely a speed optimization, as the AbstractMessage base class includes
+  // reflection-based implementations of these methods.
+  optional bool java_generate_equals_and_hash = 20 [default=false];
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;        // Generate complete code for parsing, serialization,
+                      // etc.
+    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default=SPEED];
+
+  // Sets the Go package where structs generated from this .proto will be
+  // placed.  There is no default.
+  optional string go_package = 11;
+
+
+
+  // Should generic services be generated in each language?  "Generic" services
+  // are not specific to any particular RPC system.  They are generated by the
+  // main code generators in each language (without additional plugins).
+  // Generic services were the only kind of service generation supported by
+  // early versions of proto2.
+  //
+  // Generic services are now considered deprecated in favor of using plugins
+  // that generate code specific to your particular RPC system.  Therefore,
+  // these default to false.  Old code which depends on generic services should
+  // explicitly set them to true.
+  optional bool cc_generic_services = 16 [default=false];
+  optional bool java_generic_services = 17 [default=false];
+  optional bool py_generic_services = 18 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MessageOptions {
+  // Set true to use the old proto1 MessageSet wire format for extensions.
+  // This is provided for backwards-compatibility with the MessageSet wire
+  // format.  You should not use this for any other reason:  It's less
+  // efficient, has fewer features, and is more complicated.
+  //
+  // The message must be defined exactly as follows:
+  //   message Foo {
+  //     option message_set_wire_format = true;
+  //     extensions 4 to max;
+  //   }
+  // Note that the message cannot have any defined fields; MessageSets only
+  // have extensions.
+  //
+  // All extensions of your type must be singular messages; e.g. they cannot
+  // be int32s, enums, or repeated messages.
+  //
+  // Because this is an option, the above two restrictions are not enforced by
+  // the protocol compiler.
+  optional bool message_set_wire_format = 1 [default=false];
+
+  // Disables the generation of the standard "descriptor()" accessor, which can
+  // conflict with a field of the same name.  This is meant to make migration
+  // from proto1 easier; new code should avoid fields named "descriptor".
+  optional bool no_standard_descriptor_accessor = 2 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // The ctype option instructs the C++ code generator to use a different
+  // representation of the field than it normally would.  See the specific
+  // options below.  This option is not yet implemented in the open source
+  // release -- sorry, we'll try to include it in a future version!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // The packed option can be enabled for repeated primitive fields to enable
+  // a more efficient representation on the wire. Rather than repeatedly
+  // writing the tag and type for each element, the entire array is encoded as
+  // a single length-delimited blob.
+  optional bool packed = 2;
+
+
+
+  // Should this field be parsed lazily?  Lazy applies only to message-type
+  // fields.  It means that when the outer message is initially parsed, the
+  // inner message's contents will not be parsed but instead stored in encoded
+  // form.  The inner message will actually be parsed when it is first accessed.
+  //
+  // This is only a hint.  Implementations are free to choose whether to use
+  // eager or lazy parsing regardless of the value of this option.  However,
+  // setting this option true suggests that the protocol author believes that
+  // using lazy parsing on this field is worth the additional bookkeeping
+  // overhead typically needed to implement it.
+  //
+  // This option does not affect the public interface of any generated code;
+  // all method signatures remain the same.  Furthermore, thread-safety of the
+  // interface is not affected by this option; const methods remain safe to
+  // call from multiple threads concurrently, while non-const methods continue
+  // to require exclusive access.
+  //
+  //
+  // Note that implementations may choose not to check required fields within
+  // a lazy sub-message.  That is, calling IsInitialized() on the outher message
+  // may return true even if the inner message has missing required fields.
+  // This is necessary because otherwise the inner message would have to be
+  // parsed in order to perform the check, defeating the purpose of lazy
+  // parsing.  An implementation which chooses not to check required fields
+  // must be consistent about it.  That is, for any particular sub-message, the
+  // implementation must either *always* check its required fields, or *never*
+  // check its required fields, regardless of whether or not the message has
+  // been parsed.
+  optional bool lazy = 5 [default=false];
+
+  // Is this field deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for accessors, or it will be completely ignored; in the very least, this
+  // is a formalization for deprecating fields.
+  optional bool deprecated = 3 [default=false];
+
+  // EXPERIMENTAL.  DO NOT USE.
+  // For "map" fields, the name of the field in the enclosed type that
+  // is the key for this map.  For example, suppose we have:
+  //   message Item {
+  //     required string name = 1;
+  //     required string value = 2;
+  //   }
+  //   message Config {
+  //     repeated Item items = 1 [experimental_map_key="name"];
+  //   }
+  // In this situation, the map key for Item will be set to "name".
+  // TODO: Fully-implement this, then remove the "experimental_" prefix.
+  optional string experimental_map_key = 9;
+
+  // For Google-internal migration only. Do not use.
+  optional bool weak = 10 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // Set this option to false to disallow mapping different tag names to a same
+  // value.
+  optional bool allow_alias = 2 [default=true];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+  // The name of the uninterpreted option.  Each string represents a segment in
+  // a dot-separated name.  is_extension is true iff a segment represents an
+  // extension (denoted with parentheses in options specs in .proto files).
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+  // "foo.(bar.baz).qux".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // A Location identifies a piece of source code in a .proto file which
+  // corresponds to a particular definition.  This information is intended
+  // to be useful to IDEs, code indexers, documentation generators, and similar
+  // tools.
+  //
+  // For example, say we have a file like:
+  //   message Foo {
+  //     optional string foo = 1;
+  //   }
+  // Let's look at just the field definition:
+  //   optional string foo = 1;
+  //   ^       ^^     ^^  ^  ^^^
+  //   a       bc     de  f  ghi
+  // We have the following locations:
+  //   span   path               represents
+  //   [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+  //   [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+  //   [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+  //   [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+  //   [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+  //
+  // Notes:
+  // - A location may refer to a repeated field itself (i.e. not to any
+  //   particular index within it).  This is used whenever a set of elements are
+  //   logically enclosed in a single code segment.  For example, an entire
+  //   extend block (possibly containing multiple extension definitions) will
+  //   have an outer location whose path refers to the "extensions" repeated
+  //   field without an index.
+  // - Multiple locations may have the same path.  This happens when a single
+  //   logical declaration is spread out across multiple places.  The most
+  //   obvious example is the "extend" block again -- there may be multiple
+  //   extend blocks in the same scope, each of which will have the same path.
+  // - A location's span is not always a subset of its parent's span.  For
+  //   example, the "extendee" of an extension declaration appears at the
+  //   beginning of the "extend" block and is shared by all extensions within
+  //   the block.
+  // - Just because a location's span is a subset of some other location's span
+  //   does not mean that it is a descendent.  For example, a "group" defines
+  //   both a type and a field in a single declaration.  Thus, the locations
+  //   corresponding to the type and field and their components will overlap.
+  // - Code which tries to interpret locations should probably be designed to
+  //   ignore those that it doesn't understand, as more types of locations could
+  //   be recorded in the future.
+  repeated Location location = 1;
+  message Location {
+    // Identifies which part of the FileDescriptorProto was defined at this
+    // location.
+    //
+    // Each element is a field number or an index.  They form a path from
+    // the root FileDescriptorProto to the place where the definition.  For
+    // example, this path:
+    //   [ 4, 3, 2, 7, 1 ]
+    // refers to:
+    //   file.message_type(3)  // 4, 3
+    //       .field(7)         // 2, 7
+    //       .name()           // 1
+    // This is because FileDescriptorProto.message_type has field number 4:
+    //   repeated DescriptorProto message_type = 4;
+    // and DescriptorProto.field has field number 2:
+    //   repeated FieldDescriptorProto field = 2;
+    // and FieldDescriptorProto.name has field number 1:
+    //   optional string name = 1;
+    //
+    // Thus, the above path gives the location of a field name.  If we removed
+    // the last element:
+    //   [ 4, 3, 2, 7 ]
+    // this path refers to the whole field declaration (from the beginning
+    // of the label to the terminating semicolon).
+    repeated int32 path = 1 [packed=true];
+
+    // Always has exactly three or four elements: start line, start column,
+    // end line (optional, otherwise assumed same as start line), end column.
+    // These are packed into a single field for efficiency.  Note that line
+    // and column numbers are zero-based -- typically you will want to add
+    // 1 to each before displaying to a user.
+    repeated int32 span = 2 [packed=true];
+
+    // If this SourceCodeInfo represents a complete declaration, these are any
+    // comments appearing before and after the declaration which appear to be
+    // attached to the declaration.
+    //
+    // A series of line comments appearing on consecutive lines, with no other
+    // tokens appearing on those lines, will be treated as a single comment.
+    //
+    // Only the comment content is provided; comment markers (e.g. //) are
+    // stripped out.  For block comments, leading whitespace and an asterisk
+    // will be stripped from the beginning of each line other than the first.
+    // Newlines are included in the output.
+    //
+    // Examples:
+    //
+    //   optional int32 foo = 1;  // Comment attached to foo.
+    //   // Comment attached to bar.
+    //   optional int32 bar = 2;
+    //
+    //   optional string baz = 3;
+    //   // Comment attached to baz.
+    //   // Another line attached to baz.
+    //
+    //   // Comment attached to qux.
+    //   //
+    //   // Another line attached to qux.
+    //   optional double qux = 4;
+    //
+    //   optional string corge = 5;
+    //   /* Block comment attached
+    //    * to corge.  Leading asterisks
+    //    * will be removed. */
+    //   /* Block comment attached to
+    //    * grault. */
+    //   optional int32 grault = 6;
+    optional string leading_comments = 3;
+    optional string trailing_comments = 4;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest.proto
new file mode 100644
index 0000000..6eb2d86
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest.proto
@@ -0,0 +1,719 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;     // auto-added
+
+import "google/protobuf/unittest_import.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Protos optimized for SPEED use a strict superset of the generated code
+// of equivalent ones optimized for CODE_SIZE, so we should optimize all our
+// tests for speed unless explicitly testing code size optimization.
+option optimize_for = SPEED;
+
+option java_outer_classname = "UnittestProto";
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage                        optional_nested_message  = 18;
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  optional NestedEnum                           optional_nested_enum     = 21;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnum    optional_import_enum     = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated protobuf_unittest_import.ImportEnum    repeated_import_enum     = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum  default_nested_enum  = 81 [default = BAR        ];
+  optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+      default_import_enum = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+}
+
+message TestDeprecatedFields {
+  optional int32 deprecated_int32 = 1 [deprecated=true];
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  optional int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestAllExtensions {
+  extensions 1 to max;
+}
+
+extend TestAllExtensions {
+  // Singular
+  optional    int32 optional_int32_extension    =  1;
+  optional    int64 optional_int64_extension    =  2;
+  optional   uint32 optional_uint32_extension   =  3;
+  optional   uint64 optional_uint64_extension   =  4;
+  optional   sint32 optional_sint32_extension   =  5;
+  optional   sint64 optional_sint64_extension   =  6;
+  optional  fixed32 optional_fixed32_extension  =  7;
+  optional  fixed64 optional_fixed64_extension  =  8;
+  optional sfixed32 optional_sfixed32_extension =  9;
+  optional sfixed64 optional_sfixed64_extension = 10;
+  optional    float optional_float_extension    = 11;
+  optional   double optional_double_extension   = 12;
+  optional     bool optional_bool_extension     = 13;
+  optional   string optional_string_extension   = 14;
+  optional    bytes optional_bytes_extension    = 15;
+
+  optional group OptionalGroup_extension = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypes.NestedMessage optional_nested_message_extension = 18;
+  optional ForeignMessage optional_foreign_message_extension = 19;
+  optional protobuf_unittest_import.ImportMessage
+    optional_import_message_extension = 20;
+
+  optional TestAllTypes.NestedEnum optional_nested_enum_extension = 21;
+  optional ForeignEnum optional_foreign_enum_extension = 22;
+  optional protobuf_unittest_import.ImportEnum
+    optional_import_enum_extension = 23;
+
+  optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
+  optional string optional_cord_extension = 25 [ctype=CORD];
+
+  optional protobuf_unittest_import.PublicImportMessage
+    optional_public_import_message_extension = 26;
+
+  optional TestAllTypes.NestedMessage
+    optional_lazy_message_extension = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32_extension    = 31;
+  repeated    int64 repeated_int64_extension    = 32;
+  repeated   uint32 repeated_uint32_extension   = 33;
+  repeated   uint64 repeated_uint64_extension   = 34;
+  repeated   sint32 repeated_sint32_extension   = 35;
+  repeated   sint64 repeated_sint64_extension   = 36;
+  repeated  fixed32 repeated_fixed32_extension  = 37;
+  repeated  fixed64 repeated_fixed64_extension  = 38;
+  repeated sfixed32 repeated_sfixed32_extension = 39;
+  repeated sfixed64 repeated_sfixed64_extension = 40;
+  repeated    float repeated_float_extension    = 41;
+  repeated   double repeated_double_extension   = 42;
+  repeated     bool repeated_bool_extension     = 43;
+  repeated   string repeated_string_extension   = 44;
+  repeated    bytes repeated_bytes_extension    = 45;
+
+  repeated group RepeatedGroup_extension = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 48;
+  repeated ForeignMessage repeated_foreign_message_extension = 49;
+  repeated protobuf_unittest_import.ImportMessage
+    repeated_import_message_extension = 50;
+
+  repeated TestAllTypes.NestedEnum repeated_nested_enum_extension = 51;
+  repeated ForeignEnum repeated_foreign_enum_extension = 52;
+  repeated protobuf_unittest_import.ImportEnum
+    repeated_import_enum_extension = 53;
+
+  repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord_extension = 55 [ctype=CORD];
+
+  repeated TestAllTypes.NestedMessage
+    repeated_lazy_message_extension = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32_extension    = 61 [default =  41    ];
+  optional    int64 default_int64_extension    = 62 [default =  42    ];
+  optional   uint32 default_uint32_extension   = 63 [default =  43    ];
+  optional   uint64 default_uint64_extension   = 64 [default =  44    ];
+  optional   sint32 default_sint32_extension   = 65 [default = -45    ];
+  optional   sint64 default_sint64_extension   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32_extension  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64_extension  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32_extension = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64_extension = 70 [default = -50    ];
+  optional    float default_float_extension    = 71 [default =  51.5  ];
+  optional   double default_double_extension   = 72 [default =  52e3  ];
+  optional     bool default_bool_extension     = 73 [default = true   ];
+  optional   string default_string_extension   = 74 [default = "hello"];
+  optional    bytes default_bytes_extension    = 75 [default = "world"];
+
+  optional TestAllTypes.NestedEnum
+    default_nested_enum_extension = 81 [default = BAR];
+  optional ForeignEnum
+    default_foreign_enum_extension = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+    default_import_enum_extension = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece_extension = 84 [ctype=STRING_PIECE,
+                                                       default="abc"];
+  optional string default_cord_extension = 85 [ctype=CORD, default="123"];
+}
+
+message TestNestedExtension {
+  extend TestAllExtensions {
+    // Check for bug where string extensions declared in tested scope did not
+    // compile.
+    optional string test = 1002 [default="test"];
+  }
+}
+
+// We have separate messages for testing required fields because it's
+// annoying to have to fill in required fields in TestProto in order to
+// do anything with it.  Note that we don't need to test every type of
+// required filed because the code output is basically identical to
+// optional fields for all types.
+message TestRequired {
+  required int32 a = 1;
+  optional int32 dummy2 = 2;
+  required int32 b = 3;
+
+  extend TestAllExtensions {
+    optional TestRequired single = 1000;
+    repeated TestRequired multi  = 1001;
+  }
+
+  // Pad the field count to 32 so that we can test that IsInitialized()
+  // properly checks multiple elements of has_bits_.
+  optional int32 dummy4  =  4;
+  optional int32 dummy5  =  5;
+  optional int32 dummy6  =  6;
+  optional int32 dummy7  =  7;
+  optional int32 dummy8  =  8;
+  optional int32 dummy9  =  9;
+  optional int32 dummy10 = 10;
+  optional int32 dummy11 = 11;
+  optional int32 dummy12 = 12;
+  optional int32 dummy13 = 13;
+  optional int32 dummy14 = 14;
+  optional int32 dummy15 = 15;
+  optional int32 dummy16 = 16;
+  optional int32 dummy17 = 17;
+  optional int32 dummy18 = 18;
+  optional int32 dummy19 = 19;
+  optional int32 dummy20 = 20;
+  optional int32 dummy21 = 21;
+  optional int32 dummy22 = 22;
+  optional int32 dummy23 = 23;
+  optional int32 dummy24 = 24;
+  optional int32 dummy25 = 25;
+  optional int32 dummy26 = 26;
+  optional int32 dummy27 = 27;
+  optional int32 dummy28 = 28;
+  optional int32 dummy29 = 29;
+  optional int32 dummy30 = 30;
+  optional int32 dummy31 = 31;
+  optional int32 dummy32 = 32;
+
+  required int32 c = 33;
+}
+
+message TestRequiredForeign {
+  optional TestRequired optional_message = 1;
+  repeated TestRequired repeated_message = 2;
+  optional int32 dummy = 3;
+}
+
+// Test that we can use NestedMessage from outside TestAllTypes.
+message TestForeignNested {
+  optional TestAllTypes.NestedMessage foreign_nested = 1;
+}
+
+// TestEmptyMessage is used to test unknown field support.
+message TestEmptyMessage {
+}
+
+// Like above, but declare all field numbers as potential extensions.  No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensions {
+  extensions 1 to max;
+}
+
+message TestMultipleExtensionRanges {
+  extensions 42;
+  extensions 4143 to 4243;
+  extensions 65536 to max;
+}
+
+// Test that really large tag numbers don't break anything.
+message TestReallyLargeTagNumber {
+  // The largest possible tag number is 2^28 - 1, since the wire format uses
+  // three bits to communicate wire type.
+  optional int32 a = 1;
+  optional int32 bb = 268435455;
+}
+
+message TestRecursiveMessage {
+  optional TestRecursiveMessage a = 1;
+  optional int32 i = 2;
+}
+
+// Test that mutual recursion works.
+message TestMutualRecursionA {
+  optional TestMutualRecursionB bb = 1;
+}
+
+message TestMutualRecursionB {
+  optional TestMutualRecursionA a = 1;
+  optional int32 optional_int32 = 2;
+}
+
+// Test that groups have disjoint field numbers from their siblings and
+// parents.  This is NOT possible in proto1; only proto2.  When attempting
+// to compile with proto1, this will emit an error; so we only include it
+// in protobuf_unittest_proto.
+message TestDupFieldNumber {                        // NO_PROTO1
+  optional int32 a = 1;                             // NO_PROTO1
+  optional group Foo = 2 { optional int32 a = 1; }  // NO_PROTO1
+  optional group Bar = 3 { optional int32 a = 1; }  // NO_PROTO1
+}                                                   // NO_PROTO1
+
+// Additional messages for testing lazy fields.
+message TestEagerMessage {
+  optional TestAllTypes sub_message = 1 [lazy=false];
+}
+message TestLazyMessage {
+  optional TestAllTypes sub_message = 1 [lazy=true];
+}
+
+// Needed for a Python test.
+message TestNestedMessageHasBits {
+  message NestedMessage {
+    repeated int32 nestedmessage_repeated_int32 = 1;
+    repeated ForeignMessage nestedmessage_repeated_foreignmessage = 2;
+  }
+  optional NestedMessage optional_nested_message = 1;
+}
+
+
+// Test an enum that has multiple values with the same number.
+enum TestEnumWithDupValue {
+  option allow_alias = true;
+  FOO1 = 1;
+  BAR1 = 2;
+  BAZ = 3;
+  FOO2 = 1;
+  BAR2 = 2;
+}
+
+// Test an enum with large, unordered values.
+enum TestSparseEnum {
+  SPARSE_A = 123;
+  SPARSE_B = 62374;
+  SPARSE_C = 12589234;
+  SPARSE_D = -15;
+  SPARSE_E = -53452;
+  SPARSE_F = 0;
+  SPARSE_G = 2;
+}
+
+// Test message with CamelCase field names.  This violates Protocol Buffer
+// standard style.
+message TestCamelCaseFieldNames {
+  optional int32 PrimitiveField = 1;
+  optional string StringField = 2;
+  optional ForeignEnum EnumField = 3;
+  optional ForeignMessage MessageField = 4;
+  optional string StringPieceField = 5 [ctype=STRING_PIECE];
+  optional string CordField = 6 [ctype=CORD];
+
+  repeated int32 RepeatedPrimitiveField = 7;
+  repeated string RepeatedStringField = 8;
+  repeated ForeignEnum RepeatedEnumField = 9;
+  repeated ForeignMessage RepeatedMessageField = 10;
+  repeated string RepeatedStringPieceField = 11 [ctype=STRING_PIECE];
+  repeated string RepeatedCordField = 12 [ctype=CORD];
+}
+
+
+// We list fields out of order, to ensure that we're using field number and not
+// field index to determine serialization order.
+message TestFieldOrderings {
+  optional string my_string = 11;
+  extensions 2 to 10;
+  optional int64 my_int = 1;
+  extensions 12 to 100;
+  optional float my_float = 101;
+}
+
+
+extend TestFieldOrderings {
+  optional string my_extension_string = 50;
+  optional int32 my_extension_int = 5;
+}
+
+
+message TestExtremeDefaultValues {
+  optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"];
+  optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF];
+  optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
+  optional  int32 small_int32  = 4 [default = -0x7FFFFFFF];
+  optional  int64 small_int64  = 5 [default = -0x7FFFFFFFFFFFFFFF];
+  optional  int32 really_small_int32 = 21 [default = -0x80000000];
+  optional  int64 really_small_int64 = 22 [default = -0x8000000000000000];
+
+  // The default value here is UTF-8 for "\u1234".  (We could also just type
+  // the UTF-8 text directly into this text file rather than escape it, but
+  // lots of people use editors that would be confused by this.)
+  optional string utf8_string = 6 [default = "\341\210\264"];
+
+  // Tests for single-precision floating-point values.
+  optional float zero_float = 7 [default = 0];
+  optional float one_float = 8 [default = 1];
+  optional float small_float = 9 [default = 1.5];
+  optional float negative_one_float = 10 [default = -1];
+  optional float negative_float = 11 [default = -1.5];
+  // Using exponents
+  optional float large_float = 12 [default = 2E8];
+  optional float small_negative_float = 13 [default = -8e-28];
+
+  // Text for nonfinite floating-point values.
+  optional double inf_double = 14 [default = inf];
+  optional double neg_inf_double = 15 [default = -inf];
+  optional double nan_double = 16 [default = nan];
+  optional float inf_float = 17 [default = inf];
+  optional float neg_inf_float = 18 [default = -inf];
+  optional float nan_float = 19 [default = nan];
+
+  // Tests for C++ trigraphs.
+  // Trigraphs should be escaped in C++ generated files, but they should not be
+  // escaped for other languages.
+  // Note that in .proto file, "\?" is a valid way to escape ? in string
+  // literals.
+  optional string cpp_trigraph = 20 [default = "? \? ?? \?? \??? ??/ ?\?-"];
+
+  // String defaults containing the character '\000'
+  optional string string_with_zero       = 23 [default = "hel\000lo"];
+  optional  bytes bytes_with_zero        = 24 [default = "wor\000ld"];
+  optional string string_piece_with_zero = 25 [ctype=STRING_PIECE,
+                                               default="ab\000c"];
+  optional string cord_with_zero         = 26 [ctype=CORD,
+                                               default="12\0003"];
+}
+
+message SparseEnumMessage {
+  optional TestSparseEnum sparse_enum = 1;
+}
+
+// Test String and Bytes: string is for valid UTF-8 strings
+message OneString {
+  optional string data = 1;
+}
+
+message MoreString {
+  repeated string data = 1;
+}
+
+message OneBytes {
+  optional bytes data = 1;
+}
+
+message MoreBytes {
+  repeated bytes data = 1;
+}
+
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// A message with the same fields as TestPackedTypes, but without packing. Used
+// to test packed <-> unpacked wire compatibility.
+message TestUnpackedTypes {
+  repeated    int32 unpacked_int32    =  90 [packed = false];
+  repeated    int64 unpacked_int64    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 =  99 [packed = false];
+  repeated    float unpacked_float    = 100 [packed = false];
+  repeated   double unpacked_double   = 101 [packed = false];
+  repeated     bool unpacked_bool     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum  = 103 [packed = false];
+}
+
+message TestPackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+  repeated    int32 packed_int32_extension    =  90 [packed = true];
+  repeated    int64 packed_int64_extension    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension =  99 [packed = true];
+  repeated    float packed_float_extension    = 100 [packed = true];
+  repeated   double packed_double_extension   = 101 [packed = true];
+  repeated     bool packed_bool_extension     = 102 [packed = true];
+  repeated ForeignEnum packed_enum_extension  = 103 [packed = true];
+}
+
+// Used by ExtensionSetTest/DynamicExtensions.  The test actually builds
+// a set of extensions to TestAllExtensions dynamically, based on the fields
+// of this message type.
+message TestDynamicExtensions {
+  enum DynamicEnumType {
+    DYNAMIC_FOO = 2200;
+    DYNAMIC_BAR = 2201;
+    DYNAMIC_BAZ = 2202;
+  }
+  message DynamicMessageType {
+    optional int32 dynamic_field = 2100;
+  }
+
+  optional fixed32 scalar_extension = 2000;
+  optional ForeignEnum enum_extension = 2001;
+  optional DynamicEnumType dynamic_enum_extension = 2002;
+
+  optional ForeignMessage message_extension = 2003;
+  optional DynamicMessageType dynamic_message_extension = 2004;
+
+  repeated string repeated_extension = 2005;
+  repeated sint32 packed_extension = 2006 [packed = true];
+}
+
+message TestRepeatedScalarDifferentTagSizes {
+  // Parsing repeated fixed size values used to fail. This message needs to be
+  // used in order to get a tag of the right size; all of the repeated fields
+  // in TestAllTypes didn't trigger the check.
+  repeated fixed32 repeated_fixed32 = 12;
+  // Check for a varint type, just for good measure.
+  repeated int32   repeated_int32   = 13;
+
+  // These have two-byte tags.
+  repeated fixed64 repeated_fixed64 = 2046;
+  repeated int64   repeated_int64   = 2047;
+
+  // Three byte tags.
+  repeated float   repeated_float   = 262142;
+  repeated uint64  repeated_uint64  = 262143;
+}
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+message TestParsingMerge {
+  // RepeatedFieldsGenerator defines matching field types as TestParsingMerge,
+  // except that all fields are repeated. In the tests, we will serialize the
+  // RepeatedFieldsGenerator to bytes, and parse the bytes to TestParsingMerge.
+  // Repeated fields in RepeatedFieldsGenerator are expected to be merged into
+  // the corresponding required/optional fields in TestParsingMerge.
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypes field1 = 1;
+    repeated TestAllTypes field2 = 2;
+    repeated TestAllTypes field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypes field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypes field1 = 21;
+    }
+    repeated TestAllTypes ext1 = 1000;
+    repeated TestAllTypes ext2 = 1001;
+  }
+  required TestAllTypes required_all_types = 1;
+  optional TestAllTypes optional_all_types = 2;
+  repeated TestAllTypes repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypes optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypes repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMerge {
+    optional TestAllTypes optional_ext = 1000;
+    repeated TestAllTypes repeated_ext = 1001;
+  }
+}
+
+message TestCommentInjectionMessage {
+  // */ <- This should not close the generated doc comment
+  optional string a = 1 [default="*/ <- Neither should this."];
+}
+
+
+// Test that RPC services work.
+message FooRequest  {}
+message FooResponse {}
+
+message FooClientMessage {}
+message FooServerMessage{}
+
+service TestService {
+  rpc Foo(FooRequest) returns (FooResponse);
+  rpc Bar(BarRequest) returns (BarResponse);
+}
+
+
+message BarRequest  {}
+message BarResponse {}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_custom_options.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_custom_options.proto
new file mode 100644
index 0000000..e591d29
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_custom_options.proto
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: benjy@google.com (Benjy Weinberger)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file used to test the "custom options" feature of proto2.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;
+
+// A custom file option (defined below).
+option (file_opt1) = 9876543210;
+
+import "google/protobuf/descriptor.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+package protobuf_unittest;
+
+
+// Some simple test custom options of various types.
+
+extend google.protobuf.FileOptions {
+  optional uint64 file_opt1 = 7736974;
+}
+
+extend google.protobuf.MessageOptions {
+  optional int32 message_opt1 = 7739036;
+}
+
+extend google.protobuf.FieldOptions {
+  optional fixed64 field_opt1 = 7740936;
+  // This is useful for testing that we correctly register default values for
+  // extension options.
+  optional int32 field_opt2 = 7753913 [default=42];
+}
+
+extend google.protobuf.EnumOptions {
+  optional sfixed32 enum_opt1 = 7753576;
+}
+
+extend google.protobuf.EnumValueOptions {
+  optional int32 enum_value_opt1 = 1560678;
+}
+
+extend google.protobuf.ServiceOptions {
+  optional sint64 service_opt1 = 7887650;
+}
+
+enum MethodOpt1 {
+  METHODOPT1_VAL1 = 1;
+  METHODOPT1_VAL2 = 2;
+}
+
+extend google.protobuf.MethodOptions {
+  optional MethodOpt1 method_opt1 = 7890860;
+}
+
+// A test message with custom options at all possible locations (and also some
+// regular options, to make sure they interact nicely).
+message TestMessageWithCustomOptions {
+  option message_set_wire_format = false;
+
+  option (message_opt1) = -56;
+
+  optional string field1 = 1 [ctype=CORD,
+                              (field_opt1)=8765432109];
+
+  enum AnEnum {
+    option (enum_opt1) = -789;
+
+    ANENUM_VAL1 = 1;
+    ANENUM_VAL2 = 2 [(enum_value_opt1) = 123];
+  }
+}
+
+
+// A test RPC service with custom options at all possible locations (and also
+// some regular options, to make sure they interact nicely).
+message CustomOptionFooRequest {
+}
+
+message CustomOptionFooResponse {
+}
+
+message CustomOptionFooClientMessage {
+}
+
+message CustomOptionFooServerMessage {
+}
+
+service TestServiceWithCustomOptions {
+  option (service_opt1) = -9876543210;
+
+  rpc Foo(CustomOptionFooRequest) returns (CustomOptionFooResponse) {
+    option (method_opt1) = METHODOPT1_VAL2;
+  }
+}
+
+
+
+// Options of every possible field type, so we can test them all exhaustively.
+
+message DummyMessageContainingEnum {
+  enum TestEnumType {
+    TEST_OPTION_ENUM_TYPE1 = 22;
+    TEST_OPTION_ENUM_TYPE2 = -23;
+  }
+}
+
+message DummyMessageInvalidAsOptionType {
+}
+
+extend google.protobuf.MessageOptions {
+  optional         bool     bool_opt = 7706090;
+  optional        int32    int32_opt = 7705709;
+  optional        int64    int64_opt = 7705542;
+  optional       uint32   uint32_opt = 7704880;
+  optional       uint64   uint64_opt = 7702367;
+  optional       sint32   sint32_opt = 7701568;
+  optional       sint64   sint64_opt = 7700863;
+  optional      fixed32  fixed32_opt = 7700307;
+  optional      fixed64  fixed64_opt = 7700194;
+  optional     sfixed32 sfixed32_opt = 7698645;
+  optional     sfixed64 sfixed64_opt = 7685475;
+  optional        float    float_opt = 7675390;
+  optional       double   double_opt = 7673293;
+  optional       string   string_opt = 7673285;
+  optional        bytes    bytes_opt = 7673238;
+  optional DummyMessageContainingEnum.TestEnumType enum_opt = 7673233;
+  optional DummyMessageInvalidAsOptionType message_type_opt = 7665967;
+}
+
+message CustomOptionMinIntegerValues {
+  option     (bool_opt) = false;
+  option    (int32_opt) = -0x80000000;
+  option    (int64_opt) = -0x8000000000000000;
+  option   (uint32_opt) = 0;
+  option   (uint64_opt) = 0;
+  option   (sint32_opt) = -0x80000000;
+  option   (sint64_opt) = -0x8000000000000000;
+  option  (fixed32_opt) = 0;
+  option  (fixed64_opt) = 0;
+  option (sfixed32_opt) = -0x80000000;
+  option (sfixed64_opt) = -0x8000000000000000;
+}
+
+message CustomOptionMaxIntegerValues {
+  option     (bool_opt) = true;
+  option    (int32_opt) = 0x7FFFFFFF;
+  option    (int64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option   (uint32_opt) = 0xFFFFFFFF;
+  option   (uint64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option   (sint32_opt) = 0x7FFFFFFF;
+  option   (sint64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option  (fixed32_opt) = 0xFFFFFFFF;
+  option  (fixed64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option (sfixed32_opt) = 0x7FFFFFFF;
+  option (sfixed64_opt) = 0x7FFFFFFFFFFFFFFF;
+}
+
+message CustomOptionOtherValues {
+  option  (int32_opt) = -100;  // To test sign-extension.
+  option  (float_opt) = 12.3456789;
+  option (double_opt) = 1.234567890123456789;
+  option (string_opt) = "Hello, \"World\"";
+  option  (bytes_opt) = "Hello\0World";
+  option   (enum_opt) = TEST_OPTION_ENUM_TYPE2;
+}
+
+message SettingRealsFromPositiveInts {
+  option  (float_opt) = 12;
+  option (double_opt) = 154;
+}
+
+message SettingRealsFromNegativeInts {
+  option  (float_opt) = -12;
+  option  (double_opt) = -154;
+}
+
+// Options of complex message types, themselves combined and extended in
+// various ways.
+
+message ComplexOptionType1 {
+  optional int32 foo = 1;
+  optional int32 foo2 = 2;
+  optional int32 foo3 = 3;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType2 {
+  optional ComplexOptionType1 bar = 1;
+  optional int32 baz = 2;
+
+  message ComplexOptionType4 {
+    optional int32 waldo = 1;
+
+    extend google.protobuf.MessageOptions {
+      optional ComplexOptionType4 complex_opt4 = 7633546;
+    }
+  }
+
+  optional ComplexOptionType4 fred = 3;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType3 {
+  optional int32 qux = 1;
+
+  optional group ComplexOptionType5 = 2 {
+    optional int32 plugh = 3;
+  }
+}
+
+extend ComplexOptionType1 {
+  optional int32 quux = 7663707;
+  optional ComplexOptionType3 corge = 7663442;
+}
+
+extend ComplexOptionType2 {
+  optional int32 grault = 7650927;
+  optional ComplexOptionType1 garply = 7649992;
+}
+
+extend google.protobuf.MessageOptions {
+  optional protobuf_unittest.ComplexOptionType1 complex_opt1 = 7646756;
+  optional ComplexOptionType2 complex_opt2 = 7636949;
+  optional ComplexOptionType3 complex_opt3 = 7636463;
+  optional group ComplexOpt6 = 7595468 {
+    optional int32 xyzzy = 7593951;
+  }
+}
+
+// Note that we try various different ways of naming the same extension.
+message VariousComplexOptions {
+  option (.protobuf_unittest.complex_opt1).foo = 42;
+  option (protobuf_unittest.complex_opt1).(.protobuf_unittest.quux) = 324;
+  option (.protobuf_unittest.complex_opt1).(protobuf_unittest.corge).qux = 876;
+  option (complex_opt2).baz = 987;
+  option (complex_opt2).(grault) = 654;
+  option (complex_opt2).bar.foo = 743;
+  option (complex_opt2).bar.(quux) = 1999;
+  option (complex_opt2).bar.(protobuf_unittest.corge).qux = 2008;
+  option (complex_opt2).(garply).foo = 741;
+  option (complex_opt2).(garply).(.protobuf_unittest.quux) = 1998;
+  option (complex_opt2).(protobuf_unittest.garply).(corge).qux = 2121;
+  option (ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
+  option (complex_opt2).fred.waldo = 321;
+  option (protobuf_unittest.complex_opt3).qux = 9;
+  option (complex_opt3).complexoptiontype5.plugh = 22;
+  option (complexopt6).xyzzy = 24;
+}
+
+// ------------------------------------------------------
+// Definitions for testing aggregate option parsing.
+// See descriptor_unittest.cc.
+
+message AggregateMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message AggregateMessageSetElement {
+  extend AggregateMessageSet {
+    optional AggregateMessageSetElement message_set_extension = 15447542;
+  }
+  optional string s = 1;
+}
+
+// A helper type used to test aggregate option parsing
+message Aggregate {
+  optional int32 i = 1;
+  optional string s = 2;
+
+  // A nested object
+  optional Aggregate sub = 3;
+
+  // To test the parsing of extensions inside aggregate values
+  optional google.protobuf.FileOptions file = 4;
+  extend google.protobuf.FileOptions {
+    optional Aggregate nested = 15476903;
+  }
+
+  // An embedded message set
+  optional AggregateMessageSet mset = 5;
+}
+
+// Allow Aggregate to be used as an option at all possible locations
+// in the .proto grammer.
+extend google.protobuf.FileOptions      { optional Aggregate fileopt    = 15478479; }
+extend google.protobuf.MessageOptions   { optional Aggregate msgopt     = 15480088; }
+extend google.protobuf.FieldOptions     { optional Aggregate fieldopt   = 15481374; }
+extend google.protobuf.EnumOptions      { optional Aggregate enumopt    = 15483218; }
+extend google.protobuf.EnumValueOptions { optional Aggregate enumvalopt = 15486921; }
+extend google.protobuf.ServiceOptions   { optional Aggregate serviceopt = 15497145; }
+extend google.protobuf.MethodOptions    { optional Aggregate methodopt  = 15512713; }
+
+// Try using AggregateOption at different points in the proto grammar
+option (fileopt) = {
+  s: 'FileAnnotation'
+  // Also test the handling of comments
+  /* of both types */ i: 100
+
+  sub { s: 'NestedFileAnnotation' }
+
+  // Include a google.protobuf.FileOptions and recursively extend it with
+  // another fileopt.
+  file {
+    [protobuf_unittest.fileopt] {
+      s:'FileExtensionAnnotation'
+    }
+  }
+
+  // A message set inside an option value
+  mset {
+    [protobuf_unittest.AggregateMessageSetElement.message_set_extension] {
+      s: 'EmbeddedMessageSetElement'
+    }
+  }
+};
+
+message AggregateMessage {
+  option (msgopt) = { i:101 s:'MessageAnnotation' };
+  optional int32 fieldname = 1 [(fieldopt) = { s:'FieldAnnotation' }];
+}
+
+service AggregateService {
+  option (serviceopt) = { s:'ServiceAnnotation' };
+  rpc Method (AggregateMessage) returns (AggregateMessage) {
+    option (methodopt) = { s:'MethodAnnotation' };
+  }
+}
+
+enum AggregateEnum {
+  option (enumopt) = { s:'EnumAnnotation' };
+  VALUE = 1 [(enumvalopt) = { s:'EnumValueAnnotation' }];
+}
+
+// Test custom options for nested type.
+message NestedOptionType {
+  message NestedMessage {
+    option (message_opt1) = 1001;
+    optional int32 nested_field = 1 [(field_opt1) = 1002];
+  }
+  enum NestedEnum {
+    option (enum_opt1) = 1003;
+    NESTED_ENUM_VALUE = 1 [(enum_value_opt1) = 1004];
+  }
+  extend google.protobuf.FileOptions {
+    optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto
new file mode 100644
index 0000000..fa17625
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which imports a proto file that uses optimize_for = CODE_SIZE.
+
+import "google/protobuf/unittest_optimize_for.proto";
+
+package protobuf_unittest;
+
+// We optimize for speed here, but we are importing a proto that is optimized
+// for code size.
+option optimize_for = SPEED;
+
+message TestEmbedOptimizedForSize {
+  // Test that embedding a message which has optimize_for = CODE_SIZE into
+  // one optimized for speed works.
+  optional TestOptimizedForSize optional_message = 1;
+  repeated TestOptimizedForSize repeated_message = 2;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_empty.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_empty.proto
new file mode 100644
index 0000000..ab12d1f
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_empty.proto
@@ -0,0 +1,37 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file intentionally left blank.  (At one point this wouldn't compile
+// correctly.)
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto
new file mode 100644
index 0000000..bc0b7c1
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto
@@ -0,0 +1,1046 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file that has an extremely large descriptor.  Used to test that
+// descriptors over 64k don't break the string literal length limit in Java.
+
+
+package google.protobuf;
+option java_package = "com.google.protobuf";
+
+// Avoid generating insanely long methods.
+option optimize_for = CODE_SIZE;
+
+message TestEnormousDescriptor {
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1 = 1 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_2 = 2 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_3 = 3 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_4 = 4 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_5 = 5 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_6 = 6 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_7 = 7 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_8 = 8 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_9 = 9 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_10 = 10 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_11 = 11 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_12 = 12 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_13 = 13 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_14 = 14 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_15 = 15 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_16 = 16 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_17 = 17 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_18 = 18 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_19 = 19 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_20 = 20 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_21 = 21 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_22 = 22 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_23 = 23 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_24 = 24 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_25 = 25 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_26 = 26 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_27 = 27 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_28 = 28 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_29 = 29 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_30 = 30 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_31 = 31 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_32 = 32 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_33 = 33 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_34 = 34 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_35 = 35 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_36 = 36 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_37 = 37 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_38 = 38 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_39 = 39 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_40 = 40 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_41 = 41 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_42 = 42 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_43 = 43 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_44 = 44 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_45 = 45 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_46 = 46 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_47 = 47 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_48 = 48 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_49 = 49 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_50 = 50 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_51 = 51 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_52 = 52 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_53 = 53 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_54 = 54 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_55 = 55 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_56 = 56 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_57 = 57 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_58 = 58 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_59 = 59 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_60 = 60 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_61 = 61 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_62 = 62 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_63 = 63 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_64 = 64 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_65 = 65 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_66 = 66 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_67 = 67 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_68 = 68 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_69 = 69 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_70 = 70 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_71 = 71 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_72 = 72 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_73 = 73 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_74 = 74 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_75 = 75 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_76 = 76 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_77 = 77 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_78 = 78 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_79 = 79 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_80 = 80 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_81 = 81 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_82 = 82 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_83 = 83 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_84 = 84 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_85 = 85 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_86 = 86 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_87 = 87 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_88 = 88 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_89 = 89 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_90 = 90 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_91 = 91 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_92 = 92 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_93 = 93 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_94 = 94 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_95 = 95 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_96 = 96 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_97 = 97 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_98 = 98 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_99 = 99 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_100 = 100 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_101 = 101 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_102 = 102 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_103 = 103 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_104 = 104 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_105 = 105 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_106 = 106 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_107 = 107 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_108 = 108 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_109 = 109 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_110 = 110 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_111 = 111 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_112 = 112 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_113 = 113 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_114 = 114 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_115 = 115 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_116 = 116 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_117 = 117 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_118 = 118 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_119 = 119 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_120 = 120 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_121 = 121 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_122 = 122 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_123 = 123 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_124 = 124 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_125 = 125 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_126 = 126 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_127 = 127 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_128 = 128 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_129 = 129 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_130 = 130 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_131 = 131 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_132 = 132 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_133 = 133 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_134 = 134 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_135 = 135 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_136 = 136 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_137 = 137 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_138 = 138 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_139 = 139 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_140 = 140 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_141 = 141 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_142 = 142 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_143 = 143 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_144 = 144 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_145 = 145 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_146 = 146 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_147 = 147 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_148 = 148 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_149 = 149 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_150 = 150 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_151 = 151 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_152 = 152 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_153 = 153 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_154 = 154 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_155 = 155 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_156 = 156 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_157 = 157 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_158 = 158 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_159 = 159 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_160 = 160 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_161 = 161 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_162 = 162 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_163 = 163 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_164 = 164 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_165 = 165 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_166 = 166 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_167 = 167 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_168 = 168 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_169 = 169 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_170 = 170 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_171 = 171 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_172 = 172 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_173 = 173 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_174 = 174 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_175 = 175 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_176 = 176 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_177 = 177 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_178 = 178 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_179 = 179 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_180 = 180 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_181 = 181 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_182 = 182 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_183 = 183 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_184 = 184 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_185 = 185 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_186 = 186 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_187 = 187 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_188 = 188 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_189 = 189 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_190 = 190 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_191 = 191 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_192 = 192 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_193 = 193 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_194 = 194 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_195 = 195 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_196 = 196 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_197 = 197 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_198 = 198 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_199 = 199 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_200 = 200 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_201 = 201 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_202 = 202 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_203 = 203 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_204 = 204 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_205 = 205 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_206 = 206 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_207 = 207 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_208 = 208 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_209 = 209 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_210 = 210 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_211 = 211 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_212 = 212 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_213 = 213 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_214 = 214 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_215 = 215 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_216 = 216 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_217 = 217 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_218 = 218 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_219 = 219 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_220 = 220 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_221 = 221 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_222 = 222 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_223 = 223 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_224 = 224 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_225 = 225 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_226 = 226 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_227 = 227 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_228 = 228 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_229 = 229 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_230 = 230 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_231 = 231 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_232 = 232 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_233 = 233 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_234 = 234 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_235 = 235 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_236 = 236 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_237 = 237 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_238 = 238 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_239 = 239 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_240 = 240 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_241 = 241 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_242 = 242 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_243 = 243 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_244 = 244 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_245 = 245 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_246 = 246 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_247 = 247 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_248 = 248 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_249 = 249 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_250 = 250 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_251 = 251 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_252 = 252 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_253 = 253 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_254 = 254 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_255 = 255 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_256 = 256 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_257 = 257 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_258 = 258 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_259 = 259 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_260 = 260 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_261 = 261 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_262 = 262 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_263 = 263 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_264 = 264 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_265 = 265 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_266 = 266 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_267 = 267 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_268 = 268 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_269 = 269 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_270 = 270 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_271 = 271 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_272 = 272 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_273 = 273 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_274 = 274 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_275 = 275 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_276 = 276 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_277 = 277 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_278 = 278 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_279 = 279 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_280 = 280 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_281 = 281 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_282 = 282 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_283 = 283 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_284 = 284 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_285 = 285 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_286 = 286 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_287 = 287 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_288 = 288 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_289 = 289 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_290 = 290 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_291 = 291 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_292 = 292 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_293 = 293 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_294 = 294 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_295 = 295 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_296 = 296 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_297 = 297 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_298 = 298 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_299 = 299 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_300 = 300 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_301 = 301 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_302 = 302 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_303 = 303 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_304 = 304 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_305 = 305 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_306 = 306 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_307 = 307 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_308 = 308 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_309 = 309 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_310 = 310 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_311 = 311 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_312 = 312 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_313 = 313 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_314 = 314 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_315 = 315 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_316 = 316 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_317 = 317 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_318 = 318 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_319 = 319 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_320 = 320 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_321 = 321 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_322 = 322 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_323 = 323 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_324 = 324 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_325 = 325 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_326 = 326 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_327 = 327 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_328 = 328 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_329 = 329 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_330 = 330 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_331 = 331 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_332 = 332 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_333 = 333 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_334 = 334 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_335 = 335 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_336 = 336 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_337 = 337 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_338 = 338 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_339 = 339 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_340 = 340 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_341 = 341 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_342 = 342 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_343 = 343 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_344 = 344 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_345 = 345 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_346 = 346 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_347 = 347 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_348 = 348 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_349 = 349 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_350 = 350 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_351 = 351 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_352 = 352 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_353 = 353 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_354 = 354 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_355 = 355 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_356 = 356 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_357 = 357 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_358 = 358 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_359 = 359 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_360 = 360 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_361 = 361 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_362 = 362 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_363 = 363 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_364 = 364 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_365 = 365 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_366 = 366 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_367 = 367 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_368 = 368 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_369 = 369 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_370 = 370 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_371 = 371 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_372 = 372 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_373 = 373 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_374 = 374 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_375 = 375 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_376 = 376 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_377 = 377 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_378 = 378 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_379 = 379 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_380 = 380 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_381 = 381 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_382 = 382 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_383 = 383 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_384 = 384 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_385 = 385 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_386 = 386 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_387 = 387 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_388 = 388 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_389 = 389 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_390 = 390 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_391 = 391 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_392 = 392 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_393 = 393 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_394 = 394 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_395 = 395 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_396 = 396 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_397 = 397 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_398 = 398 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_399 = 399 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_400 = 400 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_401 = 401 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_402 = 402 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_403 = 403 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_404 = 404 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_405 = 405 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_406 = 406 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_407 = 407 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_408 = 408 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_409 = 409 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_410 = 410 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_411 = 411 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_412 = 412 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_413 = 413 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_414 = 414 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_415 = 415 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_416 = 416 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_417 = 417 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_418 = 418 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_419 = 419 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_420 = 420 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_421 = 421 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_422 = 422 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_423 = 423 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_424 = 424 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_425 = 425 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_426 = 426 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_427 = 427 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_428 = 428 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_429 = 429 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_430 = 430 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_431 = 431 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_432 = 432 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_433 = 433 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_434 = 434 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_435 = 435 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_436 = 436 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_437 = 437 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_438 = 438 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_439 = 439 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_440 = 440 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_441 = 441 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_442 = 442 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_443 = 443 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_444 = 444 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_445 = 445 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_446 = 446 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_447 = 447 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_448 = 448 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_449 = 449 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_450 = 450 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_451 = 451 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_452 = 452 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_453 = 453 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_454 = 454 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_455 = 455 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_456 = 456 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_457 = 457 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_458 = 458 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_459 = 459 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_460 = 460 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_461 = 461 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_462 = 462 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_463 = 463 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_464 = 464 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_465 = 465 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_466 = 466 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_467 = 467 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_468 = 468 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_469 = 469 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_470 = 470 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_471 = 471 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_472 = 472 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_473 = 473 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_474 = 474 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_475 = 475 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_476 = 476 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_477 = 477 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_478 = 478 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_479 = 479 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_480 = 480 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_481 = 481 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_482 = 482 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_483 = 483 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_484 = 484 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_485 = 485 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_486 = 486 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_487 = 487 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_488 = 488 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_489 = 489 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_490 = 490 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_491 = 491 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_492 = 492 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_493 = 493 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_494 = 494 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_495 = 495 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_496 = 496 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_497 = 497 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_498 = 498 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_499 = 499 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_500 = 500 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_501 = 501 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_502 = 502 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_503 = 503 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_504 = 504 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_505 = 505 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_506 = 506 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_507 = 507 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_508 = 508 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_509 = 509 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_510 = 510 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_511 = 511 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_512 = 512 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_513 = 513 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_514 = 514 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_515 = 515 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_516 = 516 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_517 = 517 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_518 = 518 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_519 = 519 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_520 = 520 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_521 = 521 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_522 = 522 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_523 = 523 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_524 = 524 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_525 = 525 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_526 = 526 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_527 = 527 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_528 = 528 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_529 = 529 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_530 = 530 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_531 = 531 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_532 = 532 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_533 = 533 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_534 = 534 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_535 = 535 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_536 = 536 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_537 = 537 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_538 = 538 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_539 = 539 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_540 = 540 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_541 = 541 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_542 = 542 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_543 = 543 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_544 = 544 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_545 = 545 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_546 = 546 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_547 = 547 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_548 = 548 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_549 = 549 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_550 = 550 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_551 = 551 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_552 = 552 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_553 = 553 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_554 = 554 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_555 = 555 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_556 = 556 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_557 = 557 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_558 = 558 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_559 = 559 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_560 = 560 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_561 = 561 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_562 = 562 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_563 = 563 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_564 = 564 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_565 = 565 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_566 = 566 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_567 = 567 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_568 = 568 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_569 = 569 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_570 = 570 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_571 = 571 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_572 = 572 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_573 = 573 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_574 = 574 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_575 = 575 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_576 = 576 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_577 = 577 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_578 = 578 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_579 = 579 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_580 = 580 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_581 = 581 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_582 = 582 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_583 = 583 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_584 = 584 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_585 = 585 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_586 = 586 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_587 = 587 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_588 = 588 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_589 = 589 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_590 = 590 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_591 = 591 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_592 = 592 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_593 = 593 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_594 = 594 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_595 = 595 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_596 = 596 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_597 = 597 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_598 = 598 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_599 = 599 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_600 = 600 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_601 = 601 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_602 = 602 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_603 = 603 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_604 = 604 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_605 = 605 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_606 = 606 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_607 = 607 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_608 = 608 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_609 = 609 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_610 = 610 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_611 = 611 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_612 = 612 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_613 = 613 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_614 = 614 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_615 = 615 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_616 = 616 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_617 = 617 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_618 = 618 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_619 = 619 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_620 = 620 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_621 = 621 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_622 = 622 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_623 = 623 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_624 = 624 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_625 = 625 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_626 = 626 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_627 = 627 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_628 = 628 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_629 = 629 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_630 = 630 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_631 = 631 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_632 = 632 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_633 = 633 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_634 = 634 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_635 = 635 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_636 = 636 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_637 = 637 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_638 = 638 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_639 = 639 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_640 = 640 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_641 = 641 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_642 = 642 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_643 = 643 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_644 = 644 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_645 = 645 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_646 = 646 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_647 = 647 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_648 = 648 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_649 = 649 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_650 = 650 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_651 = 651 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_652 = 652 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_653 = 653 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_654 = 654 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_655 = 655 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_656 = 656 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_657 = 657 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_658 = 658 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_659 = 659 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_660 = 660 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_661 = 661 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_662 = 662 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_663 = 663 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_664 = 664 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_665 = 665 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_666 = 666 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_667 = 667 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_668 = 668 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_669 = 669 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_670 = 670 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_671 = 671 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_672 = 672 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_673 = 673 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_674 = 674 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_675 = 675 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_676 = 676 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_677 = 677 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_678 = 678 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_679 = 679 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_680 = 680 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_681 = 681 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_682 = 682 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_683 = 683 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_684 = 684 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_685 = 685 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_686 = 686 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_687 = 687 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_688 = 688 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_689 = 689 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_690 = 690 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_691 = 691 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_692 = 692 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_693 = 693 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_694 = 694 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_695 = 695 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_696 = 696 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_697 = 697 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_698 = 698 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_699 = 699 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_700 = 700 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_701 = 701 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_702 = 702 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_703 = 703 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_704 = 704 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_705 = 705 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_706 = 706 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_707 = 707 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_708 = 708 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_709 = 709 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_710 = 710 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_711 = 711 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_712 = 712 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_713 = 713 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_714 = 714 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_715 = 715 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_716 = 716 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_717 = 717 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_718 = 718 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_719 = 719 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_720 = 720 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_721 = 721 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_722 = 722 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_723 = 723 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_724 = 724 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_725 = 725 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_726 = 726 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_727 = 727 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_728 = 728 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_729 = 729 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_730 = 730 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_731 = 731 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_732 = 732 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_733 = 733 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_734 = 734 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_735 = 735 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_736 = 736 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_737 = 737 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_738 = 738 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_739 = 739 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_740 = 740 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_741 = 741 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_742 = 742 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_743 = 743 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_744 = 744 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_745 = 745 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_746 = 746 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_747 = 747 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_748 = 748 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_749 = 749 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_750 = 750 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_751 = 751 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_752 = 752 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_753 = 753 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_754 = 754 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_755 = 755 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_756 = 756 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_757 = 757 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_758 = 758 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_759 = 759 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_760 = 760 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_761 = 761 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_762 = 762 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_763 = 763 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_764 = 764 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_765 = 765 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_766 = 766 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_767 = 767 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_768 = 768 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_769 = 769 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_770 = 770 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_771 = 771 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_772 = 772 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_773 = 773 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_774 = 774 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_775 = 775 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_776 = 776 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_777 = 777 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_778 = 778 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_779 = 779 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_780 = 780 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_781 = 781 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_782 = 782 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_783 = 783 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_784 = 784 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_785 = 785 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_786 = 786 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_787 = 787 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_788 = 788 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_789 = 789 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_790 = 790 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_791 = 791 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_792 = 792 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_793 = 793 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_794 = 794 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_795 = 795 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_796 = 796 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_797 = 797 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_798 = 798 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_799 = 799 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_800 = 800 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_801 = 801 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_802 = 802 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_803 = 803 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_804 = 804 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_805 = 805 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_806 = 806 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_807 = 807 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_808 = 808 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_809 = 809 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_810 = 810 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_811 = 811 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_812 = 812 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_813 = 813 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_814 = 814 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_815 = 815 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_816 = 816 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_817 = 817 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_818 = 818 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_819 = 819 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_820 = 820 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_821 = 821 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_822 = 822 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_823 = 823 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_824 = 824 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_825 = 825 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_826 = 826 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_827 = 827 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_828 = 828 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_829 = 829 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_830 = 830 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_831 = 831 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_832 = 832 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_833 = 833 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_834 = 834 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_835 = 835 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_836 = 836 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_837 = 837 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_838 = 838 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_839 = 839 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_840 = 840 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_841 = 841 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_842 = 842 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_843 = 843 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_844 = 844 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_845 = 845 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_846 = 846 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_847 = 847 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_848 = 848 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_849 = 849 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_850 = 850 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_851 = 851 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_852 = 852 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_853 = 853 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_854 = 854 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_855 = 855 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_856 = 856 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_857 = 857 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_858 = 858 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_859 = 859 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_860 = 860 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_861 = 861 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_862 = 862 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_863 = 863 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_864 = 864 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_865 = 865 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_866 = 866 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_867 = 867 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_868 = 868 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_869 = 869 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_870 = 870 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_871 = 871 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_872 = 872 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_873 = 873 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_874 = 874 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_875 = 875 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_876 = 876 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_877 = 877 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_878 = 878 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_879 = 879 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_880 = 880 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_881 = 881 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_882 = 882 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_883 = 883 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_884 = 884 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_885 = 885 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_886 = 886 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_887 = 887 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_888 = 888 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_889 = 889 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_890 = 890 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_891 = 891 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_892 = 892 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_893 = 893 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_894 = 894 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_895 = 895 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_896 = 896 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_897 = 897 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_898 = 898 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_899 = 899 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_900 = 900 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_901 = 901 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_902 = 902 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_903 = 903 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_904 = 904 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_905 = 905 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_906 = 906 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_907 = 907 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_908 = 908 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_909 = 909 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_910 = 910 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_911 = 911 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_912 = 912 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_913 = 913 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_914 = 914 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_915 = 915 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_916 = 916 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_917 = 917 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_918 = 918 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_919 = 919 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_920 = 920 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_921 = 921 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_922 = 922 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_923 = 923 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_924 = 924 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_925 = 925 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_926 = 926 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_927 = 927 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_928 = 928 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_929 = 929 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_930 = 930 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_931 = 931 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_932 = 932 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_933 = 933 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_934 = 934 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_935 = 935 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_936 = 936 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_937 = 937 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_938 = 938 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_939 = 939 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_940 = 940 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_941 = 941 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_942 = 942 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_943 = 943 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_944 = 944 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_945 = 945 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_946 = 946 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_947 = 947 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_948 = 948 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_949 = 949 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_950 = 950 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_951 = 951 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_952 = 952 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_953 = 953 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_954 = 954 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_955 = 955 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_956 = 956 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_957 = 957 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_958 = 958 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_959 = 959 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_960 = 960 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_961 = 961 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_962 = 962 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_963 = 963 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_964 = 964 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_965 = 965 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_966 = 966 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_967 = 967 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_968 = 968 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_969 = 969 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_970 = 970 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_971 = 971 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_972 = 972 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_973 = 973 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_974 = 974 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_975 = 975 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_976 = 976 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_977 = 977 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_978 = 978 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_979 = 979 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_980 = 980 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_981 = 981 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_982 = 982 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_983 = 983 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_984 = 984 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_985 = 985 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_986 = 986 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_987 = 987 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_988 = 988 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_989 = 989 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_990 = 990 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_991 = 991 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_992 = 992 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_993 = 993 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_994 = 994 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_995 = 995 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_996 = 996 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_997 = 997 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_998 = 998 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_999 = 999 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000 = 1000 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import.proto
new file mode 100644
index 0000000..c115b11
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import.proto
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which is imported by unittest.proto to test importing.
+
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do
+// "using namespace unittest_import = protobuf_unittest_import".
+package protobuf_unittest_import;
+
+option optimize_for = SPEED;
+
+// Excercise the java_package option.
+option java_package = "com.google.protobuf.test";
+
+// Do not set a java_outer_classname here to verify that Proto2 works without
+// one.
+
+// Test public import
+import public "google/protobuf/unittest_import_public.proto";
+
+message ImportMessage {
+  optional int32 d = 1;
+}
+
+enum ImportEnum {
+  IMPORT_FOO = 7;
+  IMPORT_BAR = 8;
+  IMPORT_BAZ = 9;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_lite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_lite.proto
new file mode 100644
index 0000000..81b117f
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_lite.proto
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest_import.proto but with optimize_for = LITE_RUNTIME.
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+import public "google/protobuf/unittest_import_public_lite.proto";
+
+message ImportMessageLite {
+  optional int32 d = 1;
+}
+
+enum ImportEnumLite {
+  IMPORT_LITE_FOO = 7;
+  IMPORT_LITE_BAR = 8;
+  IMPORT_LITE_BAZ = 9;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public.proto
new file mode 100644
index 0000000..ea5d1b1
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+
+message PublicImportMessage {
+  optional int32 e = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public_lite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public_lite.proto
new file mode 100644
index 0000000..d077563
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_import_public_lite.proto
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+message PublicImportMessageLite {
+  optional int32 e = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite.proto
new file mode 100644
index 0000000..a1764aa
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite.proto
@@ -0,0 +1,360 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest.proto but with optimize_for = LITE_RUNTIME.
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest_import_lite.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+// Same as TestAllTypes but with the lite runtime.
+message TestAllTypesLite {
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+  optional ForeignMessageLite optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessageLite
+    optional_import_message = 20;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+  optional ForeignEnumLite optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnumLite optional_import_enum = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessageLite
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+  repeated ForeignMessageLite repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessageLite
+    repeated_import_message = 50;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+  repeated ForeignEnumLite repeated_foreign_enum = 52;
+  repeated protobuf_unittest_import.ImportEnumLite repeated_import_enum = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+  optional ForeignEnumLite default_foreign_enum = 82
+      [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite
+      default_import_enum = 83 [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+}
+
+message ForeignMessageLite {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumLite {
+  FOREIGN_LITE_FOO = 4;
+  FOREIGN_LITE_BAR = 5;
+  FOREIGN_LITE_BAZ = 6;
+}
+
+message TestPackedTypesLite {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnumLite packed_enum  = 103 [packed = true];
+}
+
+message TestAllExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestAllExtensionsLite {
+  // Singular
+  optional    int32 optional_int32_extension_lite    =  1;
+  optional    int64 optional_int64_extension_lite    =  2;
+  optional   uint32 optional_uint32_extension_lite   =  3;
+  optional   uint64 optional_uint64_extension_lite   =  4;
+  optional   sint32 optional_sint32_extension_lite   =  5;
+  optional   sint64 optional_sint64_extension_lite   =  6;
+  optional  fixed32 optional_fixed32_extension_lite  =  7;
+  optional  fixed64 optional_fixed64_extension_lite  =  8;
+  optional sfixed32 optional_sfixed32_extension_lite =  9;
+  optional sfixed64 optional_sfixed64_extension_lite = 10;
+  optional    float optional_float_extension_lite    = 11;
+  optional   double optional_double_extension_lite   = 12;
+  optional     bool optional_bool_extension_lite     = 13;
+  optional   string optional_string_extension_lite   = 14;
+  optional    bytes optional_bytes_extension_lite    = 15;
+
+  optional group OptionalGroup_extension_lite = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypesLite.NestedMessage optional_nested_message_extension_lite
+      = 18;
+  optional ForeignMessageLite optional_foreign_message_extension_lite = 19;
+  optional protobuf_unittest_import.ImportMessageLite
+    optional_import_message_extension_lite = 20;
+
+  optional TestAllTypesLite.NestedEnum optional_nested_enum_extension_lite = 21;
+  optional ForeignEnumLite optional_foreign_enum_extension_lite = 22;
+  optional protobuf_unittest_import.ImportEnumLite
+    optional_import_enum_extension_lite = 23;
+
+  optional string optional_string_piece_extension_lite = 24
+      [ctype=STRING_PIECE];
+  optional string optional_cord_extension_lite = 25 [ctype=CORD];
+
+  optional protobuf_unittest_import.PublicImportMessageLite
+    optional_public_import_message_extension_lite = 26;
+
+  optional TestAllTypesLite.NestedMessage
+    optional_lazy_message_extension_lite = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32_extension_lite    = 31;
+  repeated    int64 repeated_int64_extension_lite    = 32;
+  repeated   uint32 repeated_uint32_extension_lite   = 33;
+  repeated   uint64 repeated_uint64_extension_lite   = 34;
+  repeated   sint32 repeated_sint32_extension_lite   = 35;
+  repeated   sint64 repeated_sint64_extension_lite   = 36;
+  repeated  fixed32 repeated_fixed32_extension_lite  = 37;
+  repeated  fixed64 repeated_fixed64_extension_lite  = 38;
+  repeated sfixed32 repeated_sfixed32_extension_lite = 39;
+  repeated sfixed64 repeated_sfixed64_extension_lite = 40;
+  repeated    float repeated_float_extension_lite    = 41;
+  repeated   double repeated_double_extension_lite   = 42;
+  repeated     bool repeated_bool_extension_lite     = 43;
+  repeated   string repeated_string_extension_lite   = 44;
+  repeated    bytes repeated_bytes_extension_lite    = 45;
+
+  repeated group RepeatedGroup_extension_lite = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypesLite.NestedMessage repeated_nested_message_extension_lite
+      = 48;
+  repeated ForeignMessageLite repeated_foreign_message_extension_lite = 49;
+  repeated protobuf_unittest_import.ImportMessageLite
+    repeated_import_message_extension_lite = 50;
+
+  repeated TestAllTypesLite.NestedEnum repeated_nested_enum_extension_lite = 51;
+  repeated ForeignEnumLite repeated_foreign_enum_extension_lite = 52;
+  repeated protobuf_unittest_import.ImportEnumLite
+    repeated_import_enum_extension_lite = 53;
+
+  repeated string repeated_string_piece_extension_lite = 54
+      [ctype=STRING_PIECE];
+  repeated string repeated_cord_extension_lite = 55 [ctype=CORD];
+
+  repeated TestAllTypesLite.NestedMessage
+    repeated_lazy_message_extension_lite = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32_extension_lite    = 61 [default =  41    ];
+  optional    int64 default_int64_extension_lite    = 62 [default =  42    ];
+  optional   uint32 default_uint32_extension_lite   = 63 [default =  43    ];
+  optional   uint64 default_uint64_extension_lite   = 64 [default =  44    ];
+  optional   sint32 default_sint32_extension_lite   = 65 [default = -45    ];
+  optional   sint64 default_sint64_extension_lite   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32_extension_lite  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64_extension_lite  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32_extension_lite = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64_extension_lite = 70 [default = -50    ];
+  optional    float default_float_extension_lite    = 71 [default =  51.5  ];
+  optional   double default_double_extension_lite   = 72 [default =  52e3  ];
+  optional     bool default_bool_extension_lite     = 73 [default = true   ];
+  optional   string default_string_extension_lite   = 74 [default = "hello"];
+  optional    bytes default_bytes_extension_lite    = 75 [default = "world"];
+
+  optional TestAllTypesLite.NestedEnum
+    default_nested_enum_extension_lite = 81 [default = BAR];
+  optional ForeignEnumLite
+    default_foreign_enum_extension_lite = 82 [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite
+    default_import_enum_extension_lite = 83 [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece_extension_lite = 84 [ctype=STRING_PIECE,
+                                                            default="abc"];
+  optional string default_cord_extension_lite = 85 [ctype=CORD, default="123"];
+}
+
+message TestPackedExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensionsLite {
+  repeated    int32 packed_int32_extension_lite    =  90 [packed = true];
+  repeated    int64 packed_int64_extension_lite    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension_lite   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension_lite   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension_lite   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension_lite   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension_lite  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension_lite  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension_lite =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension_lite =  99 [packed = true];
+  repeated    float packed_float_extension_lite    = 100 [packed = true];
+  repeated   double packed_double_extension_lite   = 101 [packed = true];
+  repeated     bool packed_bool_extension_lite     = 102 [packed = true];
+  repeated ForeignEnumLite packed_enum_extension_lite = 103 [packed = true];
+}
+
+message TestNestedExtensionLite {
+  extend TestAllExtensionsLite {
+    optional int32 nested_extension = 12345;
+  }
+}
+
+// Test that deprecated fields work.  We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedLite {
+  optional int32 deprecated_field = 1 [deprecated = true];
+}
+
+// See the comments of the same type in unittest.proto.
+message TestParsingMergeLite {
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypesLite field1 = 1;
+    repeated TestAllTypesLite field2 = 2;
+    repeated TestAllTypesLite field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypesLite field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypesLite field1 = 21;
+    }
+    repeated TestAllTypesLite ext1 = 1000;
+    repeated TestAllTypesLite ext2 = 1001;
+  }
+  required TestAllTypesLite required_all_types = 1;
+  optional TestAllTypesLite optional_all_types = 2;
+  repeated TestAllTypesLite repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypesLite optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypesLite repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMergeLite {
+    optional TestAllTypesLite optional_ext = 1000;
+    repeated TestAllTypesLite repeated_ext = 1001;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto
new file mode 100644
index 0000000..d52cb8c
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// Tests that a "lite" message can import a regular message.
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+message TestLiteImportsNonlite {
+  optional TestAllTypes message = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_mset.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_mset.proto
new file mode 100644
index 0000000..3497f09
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_mset.proto
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains messages for testing message_set_wire_format.
+
+package protobuf_unittest;
+
+option optimize_for = SPEED;
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message TestMessageSetContainer {
+  optional TestMessageSet message_set = 1;
+}
+
+message TestMessageSetExtension1 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension1 message_set_extension = 1545008;
+  }
+  optional int32 i = 15;
+}
+
+message TestMessageSetExtension2 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension2 message_set_extension = 1547769;
+  }
+  optional string str = 25;
+}
+
+// MessageSet wire format is equivalent to this.
+message RawMessageSet {
+  repeated group Item = 1 {
+    required int32 type_id = 2;
+    required bytes message = 3;
+  }
+}
+
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_no_generic_services.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_no_generic_services.proto
new file mode 100644
index 0000000..cffb412
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_no_generic_services.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+package google.protobuf.no_generic_services_test;
+
+// *_generic_services are false by default.
+
+message TestMessage {
+  optional int32 a = 1;
+  extensions 1000 to max;
+}
+
+enum TestEnum {
+  FOO = 1;
+}
+
+extend TestMessage {
+  optional int32 test_extension = 1000;
+}
+
+service TestService {
+  rpc Foo(TestMessage) returns(TestMessage);
+}
diff --git a/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_optimize_for.proto b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_optimize_for.proto
new file mode 100644
index 0000000..feecbef
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/more_protos/src/proto/google/protobuf/unittest_optimize_for.proto
@@ -0,0 +1,61 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which uses optimize_for = CODE_SIZE.
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option optimize_for = CODE_SIZE;
+
+message TestOptimizedForSize {
+  optional int32 i = 1;
+  optional ForeignMessage msg = 19;
+
+  extensions 1000 to max;
+
+  extend TestOptimizedForSize {
+    optional int32 test_extension = 1234;
+    optional TestRequiredOptimizedForSize test_extension2 = 1235;
+  }
+}
+
+message TestRequiredOptimizedForSize {
+  required int32 x = 1;
+}
+ 
+message TestOptionalOptimizedForSize {
+  optional TestRequiredOptimizedForSize o = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/pom.xml b/java/compatibility_tests/v2.5.0/pom.xml
new file mode 100644
index 0000000..83a7563
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.google.protobuf.compatibility</groupId>
+  <artifactId>compatibility-test-suite</artifactId>
+  <version>2.5.0</version>
+  <name>Protocol Buffer Java API compatibility tests</name>
+  <packaging>pom</packaging>
+  <modules>
+    <module>protos</module>
+    <module>more_protos</module>
+    <module>tests</module>
+  </modules>
+  <properties>
+    <protoc.path>protoc</protoc.path>
+    <protobuf.version>2.5.0</protobuf.version>
+
+    <protos.protoc.path>${protoc.path}</protos.protoc.path>
+    <protos.protobuf.version>${protobuf.version}</protos.protobuf.version>
+
+    <more_protos.protoc.path>${protoc.path}</more_protos.protoc.path>
+    <more_protos.protobuf.version>${protobuf.version}</more_protos.protobuf.version>
+
+    <tests.protobuf.version>${protobuf.version}</tests.protobuf.version>
+
+    <protobuf.test.source.path>.</protobuf.test.source.path>
+  </properties>
+</project>
diff --git a/java/compatibility_tests/v2.5.0/protos/pom.xml b/java/compatibility_tests/v2.5.0/protos/pom.xml
new file mode 100644
index 0000000..a22e91e
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf.compatibility</groupId>
+    <artifactId>compatibility-test-suite</artifactId>
+    <version>2.5.0</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>com.google.protobuf.compatibility</groupId>
+  <artifactId>compatibility-protos</artifactId>
+  <version>2.5.0</version>
+
+  <name>Protos for Compatibility test</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.protobuf</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${protos.protobuf.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.6.0</version>
+        <configuration>
+          <source>1.6</source>
+          <target>1.6</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <tasks>
+                <mkdir dir="target/generated-sources" />
+                <exec executable="${protos.protoc.path}">
+                  <arg value="--java_out=target/generated-sources" />
+                  <arg value="--proto_path=src/proto" />
+                  <arg value="src/proto/google/protobuf/unittest_custom_options.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_enormous_descriptor.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_import.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_import_public.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_mset.proto" />
+                  <arg value="src/proto/google/protobuf/unittest_no_generic_services.proto" />
+                  <arg value="src/proto/com/google/protobuf/nested_builders_test.proto" />
+                  <arg value="src/proto/com/google/protobuf/nested_extension.proto" />
+                  <arg value="src/proto/com/google/protobuf/non_nested_extension.proto" />
+                  <arg value="src/proto/com/google/protobuf/test_bad_identifiers.proto" />
+                </exec>
+              </tasks>
+              <sourceRoot>target/generated-sources</sourceRoot>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/multiple_files_test.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 0000000..9a04014
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/multiple_files_test.proto
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+  message NestedMessage {
+    optional int32 i = 1;
+  }
+  enum NestedEnum {
+    BAZ = 3;
+  }
+  optional NestedMessage nested = 1;
+  repeated TestAllTypes foreign = 2;
+  optional NestedEnum nested_enum = 3;
+  optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+  FOO = 1;
+  BAR = 2;
+}
+
+service ServiceWithNoOuter {
+  rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+  optional int32 extension_with_outer = 1234567;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_builders_test.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_builders_test.proto
new file mode 100644
index 0000000..abffb9d
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_builders_test.proto
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jonp@google.com (Jon Perlow)
+//
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "NestedBuilders";
+
+
+message Vehicle {
+  optional Engine engine = 1;
+  repeated Wheel wheel = 2;
+}
+
+message Engine {
+  optional int32 cylinder = 1;
+  optional int32 liters = 2;
+}
+
+message Wheel {
+  optional int32 radius = 1;
+  optional int32 width = 2;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension.proto
new file mode 100644
index 0000000..9fe5d56
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension.proto
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions. Note that this must be defined in
+// a separate file to properly test the initialization of the outer class.
+
+
+import "com/google/protobuf/non_nested_extension.proto";
+
+package protobuf_unittest;
+
+message MyNestedExtension {
+  extend MessageToBeExtended {
+    optional MessageToBeExtended recursiveExtension = 2;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension_lite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension_lite.proto
new file mode 100644
index 0000000..16ee46e
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/nested_extension_lite.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions for a MessageLite messages. Note that
+// this must be defined in a separate file to properly test the initialization
+// of the outer class.
+
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+import "com/google/protobuf/non_nested_extension_lite.proto";
+
+message MyNestedExtensionLite {
+  extend MessageLiteToBeExtended {
+    optional MessageLiteToBeExtended recursiveExtensionLite = 3;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension.proto
new file mode 100644
index 0000000..f61b419
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions.
+
+
+package protobuf_unittest;
+
+message MessageToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtension {
+}
+
+extend MessageToBeExtended {
+  optional MyNonNestedExtension nonNestedExtension = 1;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto
new file mode 100644
index 0000000..3c82659
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/non_nested_extension_lite.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions for a MessageLite messages.
+
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message MessageLiteToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtensionLite {
+}
+
+extend MessageLiteToBeExtended {
+  optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/test_bad_identifiers.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/test_bad_identifiers.proto
new file mode 100644
index 0000000..6e67d97
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jonp@google.com (Jon Perlow)
+
+// This file tests that various identifiers work as field and type names even
+// though the same identifiers are used internally by the java code generator.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+package io_protocol_tests;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TestBadIdentifiersProto";
+
+message TestMessage {
+}
+
+message Descriptor {
+  option no_standard_descriptor_accessor = true;
+  optional string descriptor = 1;
+  message NestedDescriptor {
+    option no_standard_descriptor_accessor = true;
+    optional string descriptor = 1;
+  }
+  optional NestedDescriptor nested_descriptor = 2;
+}
+
+message Parser {
+  enum ParserEnum {
+    PARSER = 1;
+  }
+  optional ParserEnum parser = 1;
+}
+
+message Deprecated {
+  enum TestEnum {
+    FOO = 1;
+  }
+
+  optional int32 field1 = 1 [deprecated=true];
+  optional TestEnum field2 = 2 [deprecated=true];
+  optional TestMessage field3 = 3 [deprecated=true];
+}
+
+message Override {
+  optional int32 override = 1;
+}
+
+message Object {
+  optional int32 object = 1;
+  optional string string_object = 2;
+}
+
+message String {
+  optional string string = 1;
+}
+
+message Integer {
+  optional int32 integer = 1;
+}
+
+message Long {
+  optional int32 long = 1;
+}
+
+message Float {
+  optional float float = 1;
+}
+
+message Double {
+  optional double double = 1;
+}
+
+service TestConflictingMethodNames {
+  rpc Override(TestMessage) returns (TestMessage);
+}
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/descriptor.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/descriptor.proto
new file mode 100644
index 0000000..a785f79
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/descriptor.proto
@@ -0,0 +1,620 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+
+package google.protobuf;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+  repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+  optional string name = 1;       // file name, relative to root of source tree
+  optional string package = 2;    // e.g. "foo", "foo.bar", etc.
+
+  // Names of files imported by this file.
+  repeated string dependency = 3;
+  // Indexes of the public imported files in the dependency list above.
+  repeated int32 public_dependency = 10;
+  // Indexes of the weak imported files in the dependency list.
+  // For Google-internal migration only. Do not use.
+  repeated int32 weak_dependency = 11;
+
+  // All top-level definitions in this file.
+  repeated DescriptorProto message_type = 4;
+  repeated EnumDescriptorProto enum_type = 5;
+  repeated ServiceDescriptorProto service = 6;
+  repeated FieldDescriptorProto extension = 7;
+
+  optional FileOptions options = 8;
+
+  // This field contains optional information about the original source code.
+  // You may safely remove this entire field whithout harming runtime
+  // functionality of the descriptors -- the information is needed only by
+  // development tools.
+  optional SourceCodeInfo source_code_info = 9;
+}
+
+// Describes a message type.
+message DescriptorProto {
+  optional string name = 1;
+
+  repeated FieldDescriptorProto field = 2;
+  repeated FieldDescriptorProto extension = 6;
+
+  repeated DescriptorProto nested_type = 3;
+  repeated EnumDescriptorProto enum_type = 4;
+
+  message ExtensionRange {
+    optional int32 start = 1;
+    optional int32 end = 2;
+  }
+  repeated ExtensionRange extension_range = 5;
+
+  optional MessageOptions options = 7;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+  enum Type {
+    // 0 is reserved for errors.
+    // Order is weird for historical reasons.
+    TYPE_DOUBLE         = 1;
+    TYPE_FLOAT          = 2;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+    // negative values are likely.
+    TYPE_INT64          = 3;
+    TYPE_UINT64         = 4;
+    // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+    // negative values are likely.
+    TYPE_INT32          = 5;
+    TYPE_FIXED64        = 6;
+    TYPE_FIXED32        = 7;
+    TYPE_BOOL           = 8;
+    TYPE_STRING         = 9;
+    TYPE_GROUP          = 10;  // Tag-delimited aggregate.
+    TYPE_MESSAGE        = 11;  // Length-delimited aggregate.
+
+    // New in version 2.
+    TYPE_BYTES          = 12;
+    TYPE_UINT32         = 13;
+    TYPE_ENUM           = 14;
+    TYPE_SFIXED32       = 15;
+    TYPE_SFIXED64       = 16;
+    TYPE_SINT32         = 17;  // Uses ZigZag encoding.
+    TYPE_SINT64         = 18;  // Uses ZigZag encoding.
+  };
+
+  enum Label {
+    // 0 is reserved for errors
+    LABEL_OPTIONAL      = 1;
+    LABEL_REQUIRED      = 2;
+    LABEL_REPEATED      = 3;
+    // TODO(sanjay): Should we add LABEL_MAP?
+  };
+
+  optional string name = 1;
+  optional int32 number = 3;
+  optional Label label = 4;
+
+  // If type_name is set, this need not be set.  If both this and type_name
+  // are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
+  optional Type type = 5;
+
+  // For message and enum types, this is the name of the type.  If the name
+  // starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+  // rules are used to find the type (i.e. first the nested types within this
+  // message are searched, then within the parent, on up to the root
+  // namespace).
+  optional string type_name = 6;
+
+  // For extensions, this is the name of the type being extended.  It is
+  // resolved in the same manner as type_name.
+  optional string extendee = 2;
+
+  // For numeric types, contains the original text representation of the value.
+  // For booleans, "true" or "false".
+  // For strings, contains the default text contents (not escaped in any way).
+  // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+  // TODO(kenton):  Base-64 encode?
+  optional string default_value = 7;
+
+  optional FieldOptions options = 8;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+  optional string name = 1;
+
+  repeated EnumValueDescriptorProto value = 2;
+
+  optional EnumOptions options = 3;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+  optional string name = 1;
+  optional int32 number = 2;
+
+  optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+  optional string name = 1;
+  repeated MethodDescriptorProto method = 2;
+
+  optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+  optional string name = 1;
+
+  // Input and output type names.  These are resolved in the same way as
+  // FieldDescriptorProto.type_name, but must refer to a message type.
+  optional string input_type = 2;
+  optional string output_type = 3;
+
+  optional MethodOptions options = 4;
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached.  These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them.  Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+//   organization, or for experimental options, use field numbers 50000
+//   through 99999.  It is up to you to ensure that you do not use the
+//   same number for multiple options.
+// * For options which will be published and used publicly by multiple
+//   independent entities, e-mail protobuf-global-extension-registry@google.com
+//   to reserve extension numbers. Simply provide your project name (e.g.
+//   Object-C plugin) and your porject website (if available) -- there's no need
+//   to explain how you intend to use them. Usually you only need one extension
+//   number. You can declare multiple options with only one extension number by
+//   putting them in a sub-message. See the Custom Options section of the docs
+//   for examples:
+//   http://code.google.com/apis/protocolbuffers/docs/proto.html#options
+//   If this turns out to be popular, a web service will be set up
+//   to automatically assign option numbers.
+
+
+message FileOptions {
+
+  // Sets the Java package where classes generated from this .proto will be
+  // placed.  By default, the proto package is used, but this is often
+  // inappropriate because proto packages do not normally start with backwards
+  // domain names.
+  optional string java_package = 1;
+
+
+  // If set, all the classes from the .proto file are wrapped in a single
+  // outer class with the given name.  This applies to both Proto1
+  // (equivalent to the old "--one_java_file" option) and Proto2 (where
+  // a .proto always translates to a single class, but you may want to
+  // explicitly choose the class name).
+  optional string java_outer_classname = 8;
+
+  // If set true, then the Java code generator will generate a separate .java
+  // file for each top-level message, enum, and service defined in the .proto
+  // file.  Thus, these types will *not* be nested inside the outer class
+  // named by java_outer_classname.  However, the outer class will still be
+  // generated to contain the file's getDescriptor() method as well as any
+  // top-level extensions defined in the file.
+  optional bool java_multiple_files = 10 [default=false];
+
+  // If set true, then the Java code generator will generate equals() and
+  // hashCode() methods for all messages defined in the .proto file. This is
+  // purely a speed optimization, as the AbstractMessage base class includes
+  // reflection-based implementations of these methods.
+  optional bool java_generate_equals_and_hash = 20 [default=false];
+
+  // Generated classes can be optimized for speed or code size.
+  enum OptimizeMode {
+    SPEED = 1;        // Generate complete code for parsing, serialization,
+                      // etc.
+    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.
+    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+  }
+  optional OptimizeMode optimize_for = 9 [default=SPEED];
+
+  // Sets the Go package where structs generated from this .proto will be
+  // placed.  There is no default.
+  optional string go_package = 11;
+
+
+
+  // Should generic services be generated in each language?  "Generic" services
+  // are not specific to any particular RPC system.  They are generated by the
+  // main code generators in each language (without additional plugins).
+  // Generic services were the only kind of service generation supported by
+  // early versions of proto2.
+  //
+  // Generic services are now considered deprecated in favor of using plugins
+  // that generate code specific to your particular RPC system.  Therefore,
+  // these default to false.  Old code which depends on generic services should
+  // explicitly set them to true.
+  optional bool cc_generic_services = 16 [default=false];
+  optional bool java_generic_services = 17 [default=false];
+  optional bool py_generic_services = 18 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MessageOptions {
+  // Set true to use the old proto1 MessageSet wire format for extensions.
+  // This is provided for backwards-compatibility with the MessageSet wire
+  // format.  You should not use this for any other reason:  It's less
+  // efficient, has fewer features, and is more complicated.
+  //
+  // The message must be defined exactly as follows:
+  //   message Foo {
+  //     option message_set_wire_format = true;
+  //     extensions 4 to max;
+  //   }
+  // Note that the message cannot have any defined fields; MessageSets only
+  // have extensions.
+  //
+  // All extensions of your type must be singular messages; e.g. they cannot
+  // be int32s, enums, or repeated messages.
+  //
+  // Because this is an option, the above two restrictions are not enforced by
+  // the protocol compiler.
+  optional bool message_set_wire_format = 1 [default=false];
+
+  // Disables the generation of the standard "descriptor()" accessor, which can
+  // conflict with a field of the same name.  This is meant to make migration
+  // from proto1 easier; new code should avoid fields named "descriptor".
+  optional bool no_standard_descriptor_accessor = 2 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message FieldOptions {
+  // The ctype option instructs the C++ code generator to use a different
+  // representation of the field than it normally would.  See the specific
+  // options below.  This option is not yet implemented in the open source
+  // release -- sorry, we'll try to include it in a future version!
+  optional CType ctype = 1 [default = STRING];
+  enum CType {
+    // Default mode.
+    STRING = 0;
+
+    CORD = 1;
+
+    STRING_PIECE = 2;
+  }
+  // The packed option can be enabled for repeated primitive fields to enable
+  // a more efficient representation on the wire. Rather than repeatedly
+  // writing the tag and type for each element, the entire array is encoded as
+  // a single length-delimited blob.
+  optional bool packed = 2;
+
+
+
+  // Should this field be parsed lazily?  Lazy applies only to message-type
+  // fields.  It means that when the outer message is initially parsed, the
+  // inner message's contents will not be parsed but instead stored in encoded
+  // form.  The inner message will actually be parsed when it is first accessed.
+  //
+  // This is only a hint.  Implementations are free to choose whether to use
+  // eager or lazy parsing regardless of the value of this option.  However,
+  // setting this option true suggests that the protocol author believes that
+  // using lazy parsing on this field is worth the additional bookkeeping
+  // overhead typically needed to implement it.
+  //
+  // This option does not affect the public interface of any generated code;
+  // all method signatures remain the same.  Furthermore, thread-safety of the
+  // interface is not affected by this option; const methods remain safe to
+  // call from multiple threads concurrently, while non-const methods continue
+  // to require exclusive access.
+  //
+  //
+  // Note that implementations may choose not to check required fields within
+  // a lazy sub-message.  That is, calling IsInitialized() on the outher message
+  // may return true even if the inner message has missing required fields.
+  // This is necessary because otherwise the inner message would have to be
+  // parsed in order to perform the check, defeating the purpose of lazy
+  // parsing.  An implementation which chooses not to check required fields
+  // must be consistent about it.  That is, for any particular sub-message, the
+  // implementation must either *always* check its required fields, or *never*
+  // check its required fields, regardless of whether or not the message has
+  // been parsed.
+  optional bool lazy = 5 [default=false];
+
+  // Is this field deprecated?
+  // Depending on the target platform, this can emit Deprecated annotations
+  // for accessors, or it will be completely ignored; in the very least, this
+  // is a formalization for deprecating fields.
+  optional bool deprecated = 3 [default=false];
+
+  // EXPERIMENTAL.  DO NOT USE.
+  // For "map" fields, the name of the field in the enclosed type that
+  // is the key for this map.  For example, suppose we have:
+  //   message Item {
+  //     required string name = 1;
+  //     required string value = 2;
+  //   }
+  //   message Config {
+  //     repeated Item items = 1 [experimental_map_key="name"];
+  //   }
+  // In this situation, the map key for Item will be set to "name".
+  // TODO: Fully-implement this, then remove the "experimental_" prefix.
+  optional string experimental_map_key = 9;
+
+  // For Google-internal migration only. Do not use.
+  optional bool weak = 10 [default=false];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumOptions {
+
+  // Set this option to false to disallow mapping different tag names to a same
+  // value.
+  optional bool allow_alias = 2 [default=true];
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message EnumValueOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+message MethodOptions {
+
+  // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
+  //   framework.  We apologize for hoarding these numbers to ourselves, but
+  //   we were already using them long before we decided to release Protocol
+  //   Buffers.
+
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+  // The name of the uninterpreted option.  Each string represents a segment in
+  // a dot-separated name.  is_extension is true iff a segment represents an
+  // extension (denoted with parentheses in options specs in .proto files).
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+  // "foo.(bar.baz).qux".
+  message NamePart {
+    required string name_part = 1;
+    required bool is_extension = 2;
+  }
+  repeated NamePart name = 2;
+
+  // The value of the uninterpreted option, in whatever type the tokenizer
+  // identified it as during parsing. Exactly one of these should be set.
+  optional string identifier_value = 3;
+  optional uint64 positive_int_value = 4;
+  optional int64 negative_int_value = 5;
+  optional double double_value = 6;
+  optional bytes string_value = 7;
+  optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+  // A Location identifies a piece of source code in a .proto file which
+  // corresponds to a particular definition.  This information is intended
+  // to be useful to IDEs, code indexers, documentation generators, and similar
+  // tools.
+  //
+  // For example, say we have a file like:
+  //   message Foo {
+  //     optional string foo = 1;
+  //   }
+  // Let's look at just the field definition:
+  //   optional string foo = 1;
+  //   ^       ^^     ^^  ^  ^^^
+  //   a       bc     de  f  ghi
+  // We have the following locations:
+  //   span   path               represents
+  //   [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+  //   [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+  //   [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+  //   [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+  //   [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+  //
+  // Notes:
+  // - A location may refer to a repeated field itself (i.e. not to any
+  //   particular index within it).  This is used whenever a set of elements are
+  //   logically enclosed in a single code segment.  For example, an entire
+  //   extend block (possibly containing multiple extension definitions) will
+  //   have an outer location whose path refers to the "extensions" repeated
+  //   field without an index.
+  // - Multiple locations may have the same path.  This happens when a single
+  //   logical declaration is spread out across multiple places.  The most
+  //   obvious example is the "extend" block again -- there may be multiple
+  //   extend blocks in the same scope, each of which will have the same path.
+  // - A location's span is not always a subset of its parent's span.  For
+  //   example, the "extendee" of an extension declaration appears at the
+  //   beginning of the "extend" block and is shared by all extensions within
+  //   the block.
+  // - Just because a location's span is a subset of some other location's span
+  //   does not mean that it is a descendent.  For example, a "group" defines
+  //   both a type and a field in a single declaration.  Thus, the locations
+  //   corresponding to the type and field and their components will overlap.
+  // - Code which tries to interpret locations should probably be designed to
+  //   ignore those that it doesn't understand, as more types of locations could
+  //   be recorded in the future.
+  repeated Location location = 1;
+  message Location {
+    // Identifies which part of the FileDescriptorProto was defined at this
+    // location.
+    //
+    // Each element is a field number or an index.  They form a path from
+    // the root FileDescriptorProto to the place where the definition.  For
+    // example, this path:
+    //   [ 4, 3, 2, 7, 1 ]
+    // refers to:
+    //   file.message_type(3)  // 4, 3
+    //       .field(7)         // 2, 7
+    //       .name()           // 1
+    // This is because FileDescriptorProto.message_type has field number 4:
+    //   repeated DescriptorProto message_type = 4;
+    // and DescriptorProto.field has field number 2:
+    //   repeated FieldDescriptorProto field = 2;
+    // and FieldDescriptorProto.name has field number 1:
+    //   optional string name = 1;
+    //
+    // Thus, the above path gives the location of a field name.  If we removed
+    // the last element:
+    //   [ 4, 3, 2, 7 ]
+    // this path refers to the whole field declaration (from the beginning
+    // of the label to the terminating semicolon).
+    repeated int32 path = 1 [packed=true];
+
+    // Always has exactly three or four elements: start line, start column,
+    // end line (optional, otherwise assumed same as start line), end column.
+    // These are packed into a single field for efficiency.  Note that line
+    // and column numbers are zero-based -- typically you will want to add
+    // 1 to each before displaying to a user.
+    repeated int32 span = 2 [packed=true];
+
+    // If this SourceCodeInfo represents a complete declaration, these are any
+    // comments appearing before and after the declaration which appear to be
+    // attached to the declaration.
+    //
+    // A series of line comments appearing on consecutive lines, with no other
+    // tokens appearing on those lines, will be treated as a single comment.
+    //
+    // Only the comment content is provided; comment markers (e.g. //) are
+    // stripped out.  For block comments, leading whitespace and an asterisk
+    // will be stripped from the beginning of each line other than the first.
+    // Newlines are included in the output.
+    //
+    // Examples:
+    //
+    //   optional int32 foo = 1;  // Comment attached to foo.
+    //   // Comment attached to bar.
+    //   optional int32 bar = 2;
+    //
+    //   optional string baz = 3;
+    //   // Comment attached to baz.
+    //   // Another line attached to baz.
+    //
+    //   // Comment attached to qux.
+    //   //
+    //   // Another line attached to qux.
+    //   optional double qux = 4;
+    //
+    //   optional string corge = 5;
+    //   /* Block comment attached
+    //    * to corge.  Leading asterisks
+    //    * will be removed. */
+    //   /* Block comment attached to
+    //    * grault. */
+    //   optional int32 grault = 6;
+    optional string leading_comments = 3;
+    optional string trailing_comments = 4;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest.proto
new file mode 100644
index 0000000..6eb2d86
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest.proto
@@ -0,0 +1,719 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;     // auto-added
+
+import "google/protobuf/unittest_import.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Protos optimized for SPEED use a strict superset of the generated code
+// of equivalent ones optimized for CODE_SIZE, so we should optimize all our
+// tests for speed unless explicitly testing code size optimization.
+option optimize_for = SPEED;
+
+option java_outer_classname = "UnittestProto";
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage                        optional_nested_message  = 18;
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  optional NestedEnum                           optional_nested_enum     = 21;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnum    optional_import_enum     = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated protobuf_unittest_import.ImportEnum    repeated_import_enum     = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum  default_nested_enum  = 81 [default = BAR        ];
+  optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+      default_import_enum = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+}
+
+message TestDeprecatedFields {
+  optional int32 deprecated_int32 = 1 [deprecated=true];
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  optional int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestAllExtensions {
+  extensions 1 to max;
+}
+
+extend TestAllExtensions {
+  // Singular
+  optional    int32 optional_int32_extension    =  1;
+  optional    int64 optional_int64_extension    =  2;
+  optional   uint32 optional_uint32_extension   =  3;
+  optional   uint64 optional_uint64_extension   =  4;
+  optional   sint32 optional_sint32_extension   =  5;
+  optional   sint64 optional_sint64_extension   =  6;
+  optional  fixed32 optional_fixed32_extension  =  7;
+  optional  fixed64 optional_fixed64_extension  =  8;
+  optional sfixed32 optional_sfixed32_extension =  9;
+  optional sfixed64 optional_sfixed64_extension = 10;
+  optional    float optional_float_extension    = 11;
+  optional   double optional_double_extension   = 12;
+  optional     bool optional_bool_extension     = 13;
+  optional   string optional_string_extension   = 14;
+  optional    bytes optional_bytes_extension    = 15;
+
+  optional group OptionalGroup_extension = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypes.NestedMessage optional_nested_message_extension = 18;
+  optional ForeignMessage optional_foreign_message_extension = 19;
+  optional protobuf_unittest_import.ImportMessage
+    optional_import_message_extension = 20;
+
+  optional TestAllTypes.NestedEnum optional_nested_enum_extension = 21;
+  optional ForeignEnum optional_foreign_enum_extension = 22;
+  optional protobuf_unittest_import.ImportEnum
+    optional_import_enum_extension = 23;
+
+  optional string optional_string_piece_extension = 24 [ctype=STRING_PIECE];
+  optional string optional_cord_extension = 25 [ctype=CORD];
+
+  optional protobuf_unittest_import.PublicImportMessage
+    optional_public_import_message_extension = 26;
+
+  optional TestAllTypes.NestedMessage
+    optional_lazy_message_extension = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32_extension    = 31;
+  repeated    int64 repeated_int64_extension    = 32;
+  repeated   uint32 repeated_uint32_extension   = 33;
+  repeated   uint64 repeated_uint64_extension   = 34;
+  repeated   sint32 repeated_sint32_extension   = 35;
+  repeated   sint64 repeated_sint64_extension   = 36;
+  repeated  fixed32 repeated_fixed32_extension  = 37;
+  repeated  fixed64 repeated_fixed64_extension  = 38;
+  repeated sfixed32 repeated_sfixed32_extension = 39;
+  repeated sfixed64 repeated_sfixed64_extension = 40;
+  repeated    float repeated_float_extension    = 41;
+  repeated   double repeated_double_extension   = 42;
+  repeated     bool repeated_bool_extension     = 43;
+  repeated   string repeated_string_extension   = 44;
+  repeated    bytes repeated_bytes_extension    = 45;
+
+  repeated group RepeatedGroup_extension = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 48;
+  repeated ForeignMessage repeated_foreign_message_extension = 49;
+  repeated protobuf_unittest_import.ImportMessage
+    repeated_import_message_extension = 50;
+
+  repeated TestAllTypes.NestedEnum repeated_nested_enum_extension = 51;
+  repeated ForeignEnum repeated_foreign_enum_extension = 52;
+  repeated protobuf_unittest_import.ImportEnum
+    repeated_import_enum_extension = 53;
+
+  repeated string repeated_string_piece_extension = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord_extension = 55 [ctype=CORD];
+
+  repeated TestAllTypes.NestedMessage
+    repeated_lazy_message_extension = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32_extension    = 61 [default =  41    ];
+  optional    int64 default_int64_extension    = 62 [default =  42    ];
+  optional   uint32 default_uint32_extension   = 63 [default =  43    ];
+  optional   uint64 default_uint64_extension   = 64 [default =  44    ];
+  optional   sint32 default_sint32_extension   = 65 [default = -45    ];
+  optional   sint64 default_sint64_extension   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32_extension  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64_extension  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32_extension = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64_extension = 70 [default = -50    ];
+  optional    float default_float_extension    = 71 [default =  51.5  ];
+  optional   double default_double_extension   = 72 [default =  52e3  ];
+  optional     bool default_bool_extension     = 73 [default = true   ];
+  optional   string default_string_extension   = 74 [default = "hello"];
+  optional    bytes default_bytes_extension    = 75 [default = "world"];
+
+  optional TestAllTypes.NestedEnum
+    default_nested_enum_extension = 81 [default = BAR];
+  optional ForeignEnum
+    default_foreign_enum_extension = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+    default_import_enum_extension = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece_extension = 84 [ctype=STRING_PIECE,
+                                                       default="abc"];
+  optional string default_cord_extension = 85 [ctype=CORD, default="123"];
+}
+
+message TestNestedExtension {
+  extend TestAllExtensions {
+    // Check for bug where string extensions declared in tested scope did not
+    // compile.
+    optional string test = 1002 [default="test"];
+  }
+}
+
+// We have separate messages for testing required fields because it's
+// annoying to have to fill in required fields in TestProto in order to
+// do anything with it.  Note that we don't need to test every type of
+// required filed because the code output is basically identical to
+// optional fields for all types.
+message TestRequired {
+  required int32 a = 1;
+  optional int32 dummy2 = 2;
+  required int32 b = 3;
+
+  extend TestAllExtensions {
+    optional TestRequired single = 1000;
+    repeated TestRequired multi  = 1001;
+  }
+
+  // Pad the field count to 32 so that we can test that IsInitialized()
+  // properly checks multiple elements of has_bits_.
+  optional int32 dummy4  =  4;
+  optional int32 dummy5  =  5;
+  optional int32 dummy6  =  6;
+  optional int32 dummy7  =  7;
+  optional int32 dummy8  =  8;
+  optional int32 dummy9  =  9;
+  optional int32 dummy10 = 10;
+  optional int32 dummy11 = 11;
+  optional int32 dummy12 = 12;
+  optional int32 dummy13 = 13;
+  optional int32 dummy14 = 14;
+  optional int32 dummy15 = 15;
+  optional int32 dummy16 = 16;
+  optional int32 dummy17 = 17;
+  optional int32 dummy18 = 18;
+  optional int32 dummy19 = 19;
+  optional int32 dummy20 = 20;
+  optional int32 dummy21 = 21;
+  optional int32 dummy22 = 22;
+  optional int32 dummy23 = 23;
+  optional int32 dummy24 = 24;
+  optional int32 dummy25 = 25;
+  optional int32 dummy26 = 26;
+  optional int32 dummy27 = 27;
+  optional int32 dummy28 = 28;
+  optional int32 dummy29 = 29;
+  optional int32 dummy30 = 30;
+  optional int32 dummy31 = 31;
+  optional int32 dummy32 = 32;
+
+  required int32 c = 33;
+}
+
+message TestRequiredForeign {
+  optional TestRequired optional_message = 1;
+  repeated TestRequired repeated_message = 2;
+  optional int32 dummy = 3;
+}
+
+// Test that we can use NestedMessage from outside TestAllTypes.
+message TestForeignNested {
+  optional TestAllTypes.NestedMessage foreign_nested = 1;
+}
+
+// TestEmptyMessage is used to test unknown field support.
+message TestEmptyMessage {
+}
+
+// Like above, but declare all field numbers as potential extensions.  No
+// actual extensions should ever be defined for this type.
+message TestEmptyMessageWithExtensions {
+  extensions 1 to max;
+}
+
+message TestMultipleExtensionRanges {
+  extensions 42;
+  extensions 4143 to 4243;
+  extensions 65536 to max;
+}
+
+// Test that really large tag numbers don't break anything.
+message TestReallyLargeTagNumber {
+  // The largest possible tag number is 2^28 - 1, since the wire format uses
+  // three bits to communicate wire type.
+  optional int32 a = 1;
+  optional int32 bb = 268435455;
+}
+
+message TestRecursiveMessage {
+  optional TestRecursiveMessage a = 1;
+  optional int32 i = 2;
+}
+
+// Test that mutual recursion works.
+message TestMutualRecursionA {
+  optional TestMutualRecursionB bb = 1;
+}
+
+message TestMutualRecursionB {
+  optional TestMutualRecursionA a = 1;
+  optional int32 optional_int32 = 2;
+}
+
+// Test that groups have disjoint field numbers from their siblings and
+// parents.  This is NOT possible in proto1; only proto2.  When attempting
+// to compile with proto1, this will emit an error; so we only include it
+// in protobuf_unittest_proto.
+message TestDupFieldNumber {                        // NO_PROTO1
+  optional int32 a = 1;                             // NO_PROTO1
+  optional group Foo = 2 { optional int32 a = 1; }  // NO_PROTO1
+  optional group Bar = 3 { optional int32 a = 1; }  // NO_PROTO1
+}                                                   // NO_PROTO1
+
+// Additional messages for testing lazy fields.
+message TestEagerMessage {
+  optional TestAllTypes sub_message = 1 [lazy=false];
+}
+message TestLazyMessage {
+  optional TestAllTypes sub_message = 1 [lazy=true];
+}
+
+// Needed for a Python test.
+message TestNestedMessageHasBits {
+  message NestedMessage {
+    repeated int32 nestedmessage_repeated_int32 = 1;
+    repeated ForeignMessage nestedmessage_repeated_foreignmessage = 2;
+  }
+  optional NestedMessage optional_nested_message = 1;
+}
+
+
+// Test an enum that has multiple values with the same number.
+enum TestEnumWithDupValue {
+  option allow_alias = true;
+  FOO1 = 1;
+  BAR1 = 2;
+  BAZ = 3;
+  FOO2 = 1;
+  BAR2 = 2;
+}
+
+// Test an enum with large, unordered values.
+enum TestSparseEnum {
+  SPARSE_A = 123;
+  SPARSE_B = 62374;
+  SPARSE_C = 12589234;
+  SPARSE_D = -15;
+  SPARSE_E = -53452;
+  SPARSE_F = 0;
+  SPARSE_G = 2;
+}
+
+// Test message with CamelCase field names.  This violates Protocol Buffer
+// standard style.
+message TestCamelCaseFieldNames {
+  optional int32 PrimitiveField = 1;
+  optional string StringField = 2;
+  optional ForeignEnum EnumField = 3;
+  optional ForeignMessage MessageField = 4;
+  optional string StringPieceField = 5 [ctype=STRING_PIECE];
+  optional string CordField = 6 [ctype=CORD];
+
+  repeated int32 RepeatedPrimitiveField = 7;
+  repeated string RepeatedStringField = 8;
+  repeated ForeignEnum RepeatedEnumField = 9;
+  repeated ForeignMessage RepeatedMessageField = 10;
+  repeated string RepeatedStringPieceField = 11 [ctype=STRING_PIECE];
+  repeated string RepeatedCordField = 12 [ctype=CORD];
+}
+
+
+// We list fields out of order, to ensure that we're using field number and not
+// field index to determine serialization order.
+message TestFieldOrderings {
+  optional string my_string = 11;
+  extensions 2 to 10;
+  optional int64 my_int = 1;
+  extensions 12 to 100;
+  optional float my_float = 101;
+}
+
+
+extend TestFieldOrderings {
+  optional string my_extension_string = 50;
+  optional int32 my_extension_int = 5;
+}
+
+
+message TestExtremeDefaultValues {
+  optional bytes escaped_bytes = 1 [default = "\0\001\a\b\f\n\r\t\v\\\'\"\xfe"];
+  optional uint32 large_uint32 = 2 [default = 0xFFFFFFFF];
+  optional uint64 large_uint64 = 3 [default = 0xFFFFFFFFFFFFFFFF];
+  optional  int32 small_int32  = 4 [default = -0x7FFFFFFF];
+  optional  int64 small_int64  = 5 [default = -0x7FFFFFFFFFFFFFFF];
+  optional  int32 really_small_int32 = 21 [default = -0x80000000];
+  optional  int64 really_small_int64 = 22 [default = -0x8000000000000000];
+
+  // The default value here is UTF-8 for "\u1234".  (We could also just type
+  // the UTF-8 text directly into this text file rather than escape it, but
+  // lots of people use editors that would be confused by this.)
+  optional string utf8_string = 6 [default = "\341\210\264"];
+
+  // Tests for single-precision floating-point values.
+  optional float zero_float = 7 [default = 0];
+  optional float one_float = 8 [default = 1];
+  optional float small_float = 9 [default = 1.5];
+  optional float negative_one_float = 10 [default = -1];
+  optional float negative_float = 11 [default = -1.5];
+  // Using exponents
+  optional float large_float = 12 [default = 2E8];
+  optional float small_negative_float = 13 [default = -8e-28];
+
+  // Text for nonfinite floating-point values.
+  optional double inf_double = 14 [default = inf];
+  optional double neg_inf_double = 15 [default = -inf];
+  optional double nan_double = 16 [default = nan];
+  optional float inf_float = 17 [default = inf];
+  optional float neg_inf_float = 18 [default = -inf];
+  optional float nan_float = 19 [default = nan];
+
+  // Tests for C++ trigraphs.
+  // Trigraphs should be escaped in C++ generated files, but they should not be
+  // escaped for other languages.
+  // Note that in .proto file, "\?" is a valid way to escape ? in string
+  // literals.
+  optional string cpp_trigraph = 20 [default = "? \? ?? \?? \??? ??/ ?\?-"];
+
+  // String defaults containing the character '\000'
+  optional string string_with_zero       = 23 [default = "hel\000lo"];
+  optional  bytes bytes_with_zero        = 24 [default = "wor\000ld"];
+  optional string string_piece_with_zero = 25 [ctype=STRING_PIECE,
+                                               default="ab\000c"];
+  optional string cord_with_zero         = 26 [ctype=CORD,
+                                               default="12\0003"];
+}
+
+message SparseEnumMessage {
+  optional TestSparseEnum sparse_enum = 1;
+}
+
+// Test String and Bytes: string is for valid UTF-8 strings
+message OneString {
+  optional string data = 1;
+}
+
+message MoreString {
+  repeated string data = 1;
+}
+
+message OneBytes {
+  optional bytes data = 1;
+}
+
+message MoreBytes {
+  repeated bytes data = 1;
+}
+
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// A message with the same fields as TestPackedTypes, but without packing. Used
+// to test packed <-> unpacked wire compatibility.
+message TestUnpackedTypes {
+  repeated    int32 unpacked_int32    =  90 [packed = false];
+  repeated    int64 unpacked_int64    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 =  99 [packed = false];
+  repeated    float unpacked_float    = 100 [packed = false];
+  repeated   double unpacked_double   = 101 [packed = false];
+  repeated     bool unpacked_bool     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum  = 103 [packed = false];
+}
+
+message TestPackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+  repeated    int32 packed_int32_extension    =  90 [packed = true];
+  repeated    int64 packed_int64_extension    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension =  99 [packed = true];
+  repeated    float packed_float_extension    = 100 [packed = true];
+  repeated   double packed_double_extension   = 101 [packed = true];
+  repeated     bool packed_bool_extension     = 102 [packed = true];
+  repeated ForeignEnum packed_enum_extension  = 103 [packed = true];
+}
+
+// Used by ExtensionSetTest/DynamicExtensions.  The test actually builds
+// a set of extensions to TestAllExtensions dynamically, based on the fields
+// of this message type.
+message TestDynamicExtensions {
+  enum DynamicEnumType {
+    DYNAMIC_FOO = 2200;
+    DYNAMIC_BAR = 2201;
+    DYNAMIC_BAZ = 2202;
+  }
+  message DynamicMessageType {
+    optional int32 dynamic_field = 2100;
+  }
+
+  optional fixed32 scalar_extension = 2000;
+  optional ForeignEnum enum_extension = 2001;
+  optional DynamicEnumType dynamic_enum_extension = 2002;
+
+  optional ForeignMessage message_extension = 2003;
+  optional DynamicMessageType dynamic_message_extension = 2004;
+
+  repeated string repeated_extension = 2005;
+  repeated sint32 packed_extension = 2006 [packed = true];
+}
+
+message TestRepeatedScalarDifferentTagSizes {
+  // Parsing repeated fixed size values used to fail. This message needs to be
+  // used in order to get a tag of the right size; all of the repeated fields
+  // in TestAllTypes didn't trigger the check.
+  repeated fixed32 repeated_fixed32 = 12;
+  // Check for a varint type, just for good measure.
+  repeated int32   repeated_int32   = 13;
+
+  // These have two-byte tags.
+  repeated fixed64 repeated_fixed64 = 2046;
+  repeated int64   repeated_int64   = 2047;
+
+  // Three byte tags.
+  repeated float   repeated_float   = 262142;
+  repeated uint64  repeated_uint64  = 262143;
+}
+
+// Test that if an optional or required message/group field appears multiple
+// times in the input, they need to be merged.
+message TestParsingMerge {
+  // RepeatedFieldsGenerator defines matching field types as TestParsingMerge,
+  // except that all fields are repeated. In the tests, we will serialize the
+  // RepeatedFieldsGenerator to bytes, and parse the bytes to TestParsingMerge.
+  // Repeated fields in RepeatedFieldsGenerator are expected to be merged into
+  // the corresponding required/optional fields in TestParsingMerge.
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypes field1 = 1;
+    repeated TestAllTypes field2 = 2;
+    repeated TestAllTypes field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypes field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypes field1 = 21;
+    }
+    repeated TestAllTypes ext1 = 1000;
+    repeated TestAllTypes ext2 = 1001;
+  }
+  required TestAllTypes required_all_types = 1;
+  optional TestAllTypes optional_all_types = 2;
+  repeated TestAllTypes repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypes optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypes repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMerge {
+    optional TestAllTypes optional_ext = 1000;
+    repeated TestAllTypes repeated_ext = 1001;
+  }
+}
+
+message TestCommentInjectionMessage {
+  // */ <- This should not close the generated doc comment
+  optional string a = 1 [default="*/ <- Neither should this."];
+}
+
+
+// Test that RPC services work.
+message FooRequest  {}
+message FooResponse {}
+
+message FooClientMessage {}
+message FooServerMessage{}
+
+service TestService {
+  rpc Foo(FooRequest) returns (FooResponse);
+  rpc Bar(BarRequest) returns (BarResponse);
+}
+
+
+message BarRequest  {}
+message BarResponse {}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_custom_options.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_custom_options.proto
new file mode 100644
index 0000000..e591d29
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_custom_options.proto
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: benjy@google.com (Benjy Weinberger)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file used to test the "custom options" feature of proto2.
+
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;
+
+// A custom file option (defined below).
+option (file_opt1) = 9876543210;
+
+import "google/protobuf/descriptor.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+package protobuf_unittest;
+
+
+// Some simple test custom options of various types.
+
+extend google.protobuf.FileOptions {
+  optional uint64 file_opt1 = 7736974;
+}
+
+extend google.protobuf.MessageOptions {
+  optional int32 message_opt1 = 7739036;
+}
+
+extend google.protobuf.FieldOptions {
+  optional fixed64 field_opt1 = 7740936;
+  // This is useful for testing that we correctly register default values for
+  // extension options.
+  optional int32 field_opt2 = 7753913 [default=42];
+}
+
+extend google.protobuf.EnumOptions {
+  optional sfixed32 enum_opt1 = 7753576;
+}
+
+extend google.protobuf.EnumValueOptions {
+  optional int32 enum_value_opt1 = 1560678;
+}
+
+extend google.protobuf.ServiceOptions {
+  optional sint64 service_opt1 = 7887650;
+}
+
+enum MethodOpt1 {
+  METHODOPT1_VAL1 = 1;
+  METHODOPT1_VAL2 = 2;
+}
+
+extend google.protobuf.MethodOptions {
+  optional MethodOpt1 method_opt1 = 7890860;
+}
+
+// A test message with custom options at all possible locations (and also some
+// regular options, to make sure they interact nicely).
+message TestMessageWithCustomOptions {
+  option message_set_wire_format = false;
+
+  option (message_opt1) = -56;
+
+  optional string field1 = 1 [ctype=CORD,
+                              (field_opt1)=8765432109];
+
+  enum AnEnum {
+    option (enum_opt1) = -789;
+
+    ANENUM_VAL1 = 1;
+    ANENUM_VAL2 = 2 [(enum_value_opt1) = 123];
+  }
+}
+
+
+// A test RPC service with custom options at all possible locations (and also
+// some regular options, to make sure they interact nicely).
+message CustomOptionFooRequest {
+}
+
+message CustomOptionFooResponse {
+}
+
+message CustomOptionFooClientMessage {
+}
+
+message CustomOptionFooServerMessage {
+}
+
+service TestServiceWithCustomOptions {
+  option (service_opt1) = -9876543210;
+
+  rpc Foo(CustomOptionFooRequest) returns (CustomOptionFooResponse) {
+    option (method_opt1) = METHODOPT1_VAL2;
+  }
+}
+
+
+
+// Options of every possible field type, so we can test them all exhaustively.
+
+message DummyMessageContainingEnum {
+  enum TestEnumType {
+    TEST_OPTION_ENUM_TYPE1 = 22;
+    TEST_OPTION_ENUM_TYPE2 = -23;
+  }
+}
+
+message DummyMessageInvalidAsOptionType {
+}
+
+extend google.protobuf.MessageOptions {
+  optional         bool     bool_opt = 7706090;
+  optional        int32    int32_opt = 7705709;
+  optional        int64    int64_opt = 7705542;
+  optional       uint32   uint32_opt = 7704880;
+  optional       uint64   uint64_opt = 7702367;
+  optional       sint32   sint32_opt = 7701568;
+  optional       sint64   sint64_opt = 7700863;
+  optional      fixed32  fixed32_opt = 7700307;
+  optional      fixed64  fixed64_opt = 7700194;
+  optional     sfixed32 sfixed32_opt = 7698645;
+  optional     sfixed64 sfixed64_opt = 7685475;
+  optional        float    float_opt = 7675390;
+  optional       double   double_opt = 7673293;
+  optional       string   string_opt = 7673285;
+  optional        bytes    bytes_opt = 7673238;
+  optional DummyMessageContainingEnum.TestEnumType enum_opt = 7673233;
+  optional DummyMessageInvalidAsOptionType message_type_opt = 7665967;
+}
+
+message CustomOptionMinIntegerValues {
+  option     (bool_opt) = false;
+  option    (int32_opt) = -0x80000000;
+  option    (int64_opt) = -0x8000000000000000;
+  option   (uint32_opt) = 0;
+  option   (uint64_opt) = 0;
+  option   (sint32_opt) = -0x80000000;
+  option   (sint64_opt) = -0x8000000000000000;
+  option  (fixed32_opt) = 0;
+  option  (fixed64_opt) = 0;
+  option (sfixed32_opt) = -0x80000000;
+  option (sfixed64_opt) = -0x8000000000000000;
+}
+
+message CustomOptionMaxIntegerValues {
+  option     (bool_opt) = true;
+  option    (int32_opt) = 0x7FFFFFFF;
+  option    (int64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option   (uint32_opt) = 0xFFFFFFFF;
+  option   (uint64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option   (sint32_opt) = 0x7FFFFFFF;
+  option   (sint64_opt) = 0x7FFFFFFFFFFFFFFF;
+  option  (fixed32_opt) = 0xFFFFFFFF;
+  option  (fixed64_opt) = 0xFFFFFFFFFFFFFFFF;
+  option (sfixed32_opt) = 0x7FFFFFFF;
+  option (sfixed64_opt) = 0x7FFFFFFFFFFFFFFF;
+}
+
+message CustomOptionOtherValues {
+  option  (int32_opt) = -100;  // To test sign-extension.
+  option  (float_opt) = 12.3456789;
+  option (double_opt) = 1.234567890123456789;
+  option (string_opt) = "Hello, \"World\"";
+  option  (bytes_opt) = "Hello\0World";
+  option   (enum_opt) = TEST_OPTION_ENUM_TYPE2;
+}
+
+message SettingRealsFromPositiveInts {
+  option  (float_opt) = 12;
+  option (double_opt) = 154;
+}
+
+message SettingRealsFromNegativeInts {
+  option  (float_opt) = -12;
+  option  (double_opt) = -154;
+}
+
+// Options of complex message types, themselves combined and extended in
+// various ways.
+
+message ComplexOptionType1 {
+  optional int32 foo = 1;
+  optional int32 foo2 = 2;
+  optional int32 foo3 = 3;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType2 {
+  optional ComplexOptionType1 bar = 1;
+  optional int32 baz = 2;
+
+  message ComplexOptionType4 {
+    optional int32 waldo = 1;
+
+    extend google.protobuf.MessageOptions {
+      optional ComplexOptionType4 complex_opt4 = 7633546;
+    }
+  }
+
+  optional ComplexOptionType4 fred = 3;
+
+  extensions 100 to max;
+}
+
+message ComplexOptionType3 {
+  optional int32 qux = 1;
+
+  optional group ComplexOptionType5 = 2 {
+    optional int32 plugh = 3;
+  }
+}
+
+extend ComplexOptionType1 {
+  optional int32 quux = 7663707;
+  optional ComplexOptionType3 corge = 7663442;
+}
+
+extend ComplexOptionType2 {
+  optional int32 grault = 7650927;
+  optional ComplexOptionType1 garply = 7649992;
+}
+
+extend google.protobuf.MessageOptions {
+  optional protobuf_unittest.ComplexOptionType1 complex_opt1 = 7646756;
+  optional ComplexOptionType2 complex_opt2 = 7636949;
+  optional ComplexOptionType3 complex_opt3 = 7636463;
+  optional group ComplexOpt6 = 7595468 {
+    optional int32 xyzzy = 7593951;
+  }
+}
+
+// Note that we try various different ways of naming the same extension.
+message VariousComplexOptions {
+  option (.protobuf_unittest.complex_opt1).foo = 42;
+  option (protobuf_unittest.complex_opt1).(.protobuf_unittest.quux) = 324;
+  option (.protobuf_unittest.complex_opt1).(protobuf_unittest.corge).qux = 876;
+  option (complex_opt2).baz = 987;
+  option (complex_opt2).(grault) = 654;
+  option (complex_opt2).bar.foo = 743;
+  option (complex_opt2).bar.(quux) = 1999;
+  option (complex_opt2).bar.(protobuf_unittest.corge).qux = 2008;
+  option (complex_opt2).(garply).foo = 741;
+  option (complex_opt2).(garply).(.protobuf_unittest.quux) = 1998;
+  option (complex_opt2).(protobuf_unittest.garply).(corge).qux = 2121;
+  option (ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
+  option (complex_opt2).fred.waldo = 321;
+  option (protobuf_unittest.complex_opt3).qux = 9;
+  option (complex_opt3).complexoptiontype5.plugh = 22;
+  option (complexopt6).xyzzy = 24;
+}
+
+// ------------------------------------------------------
+// Definitions for testing aggregate option parsing.
+// See descriptor_unittest.cc.
+
+message AggregateMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message AggregateMessageSetElement {
+  extend AggregateMessageSet {
+    optional AggregateMessageSetElement message_set_extension = 15447542;
+  }
+  optional string s = 1;
+}
+
+// A helper type used to test aggregate option parsing
+message Aggregate {
+  optional int32 i = 1;
+  optional string s = 2;
+
+  // A nested object
+  optional Aggregate sub = 3;
+
+  // To test the parsing of extensions inside aggregate values
+  optional google.protobuf.FileOptions file = 4;
+  extend google.protobuf.FileOptions {
+    optional Aggregate nested = 15476903;
+  }
+
+  // An embedded message set
+  optional AggregateMessageSet mset = 5;
+}
+
+// Allow Aggregate to be used as an option at all possible locations
+// in the .proto grammer.
+extend google.protobuf.FileOptions      { optional Aggregate fileopt    = 15478479; }
+extend google.protobuf.MessageOptions   { optional Aggregate msgopt     = 15480088; }
+extend google.protobuf.FieldOptions     { optional Aggregate fieldopt   = 15481374; }
+extend google.protobuf.EnumOptions      { optional Aggregate enumopt    = 15483218; }
+extend google.protobuf.EnumValueOptions { optional Aggregate enumvalopt = 15486921; }
+extend google.protobuf.ServiceOptions   { optional Aggregate serviceopt = 15497145; }
+extend google.protobuf.MethodOptions    { optional Aggregate methodopt  = 15512713; }
+
+// Try using AggregateOption at different points in the proto grammar
+option (fileopt) = {
+  s: 'FileAnnotation'
+  // Also test the handling of comments
+  /* of both types */ i: 100
+
+  sub { s: 'NestedFileAnnotation' }
+
+  // Include a google.protobuf.FileOptions and recursively extend it with
+  // another fileopt.
+  file {
+    [protobuf_unittest.fileopt] {
+      s:'FileExtensionAnnotation'
+    }
+  }
+
+  // A message set inside an option value
+  mset {
+    [protobuf_unittest.AggregateMessageSetElement.message_set_extension] {
+      s: 'EmbeddedMessageSetElement'
+    }
+  }
+};
+
+message AggregateMessage {
+  option (msgopt) = { i:101 s:'MessageAnnotation' };
+  optional int32 fieldname = 1 [(fieldopt) = { s:'FieldAnnotation' }];
+}
+
+service AggregateService {
+  option (serviceopt) = { s:'ServiceAnnotation' };
+  rpc Method (AggregateMessage) returns (AggregateMessage) {
+    option (methodopt) = { s:'MethodAnnotation' };
+  }
+}
+
+enum AggregateEnum {
+  option (enumopt) = { s:'EnumAnnotation' };
+  VALUE = 1 [(enumvalopt) = { s:'EnumValueAnnotation' }];
+}
+
+// Test custom options for nested type.
+message NestedOptionType {
+  message NestedMessage {
+    option (message_opt1) = 1001;
+    optional int32 nested_field = 1 [(field_opt1) = 1002];
+  }
+  enum NestedEnum {
+    option (enum_opt1) = 1003;
+    NESTED_ENUM_VALUE = 1 [(enum_value_opt1) = 1004];
+  }
+  extend google.protobuf.FileOptions {
+    optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto
new file mode 100644
index 0000000..fa17625
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_embed_optimize_for.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which imports a proto file that uses optimize_for = CODE_SIZE.
+
+import "google/protobuf/unittest_optimize_for.proto";
+
+package protobuf_unittest;
+
+// We optimize for speed here, but we are importing a proto that is optimized
+// for code size.
+option optimize_for = SPEED;
+
+message TestEmbedOptimizedForSize {
+  // Test that embedding a message which has optimize_for = CODE_SIZE into
+  // one optimized for speed works.
+  optional TestOptimizedForSize optional_message = 1;
+  repeated TestOptimizedForSize repeated_message = 2;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_empty.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_empty.proto
new file mode 100644
index 0000000..ab12d1f
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_empty.proto
@@ -0,0 +1,37 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file intentionally left blank.  (At one point this wouldn't compile
+// correctly.)
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto
new file mode 100644
index 0000000..bc0b7c1
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_enormous_descriptor.proto
@@ -0,0 +1,1046 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file that has an extremely large descriptor.  Used to test that
+// descriptors over 64k don't break the string literal length limit in Java.
+
+
+package google.protobuf;
+option java_package = "com.google.protobuf";
+
+// Avoid generating insanely long methods.
+option optimize_for = CODE_SIZE;
+
+message TestEnormousDescriptor {
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1 = 1 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_2 = 2 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_3 = 3 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_4 = 4 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_5 = 5 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_6 = 6 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_7 = 7 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_8 = 8 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_9 = 9 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_10 = 10 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_11 = 11 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_12 = 12 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_13 = 13 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_14 = 14 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_15 = 15 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_16 = 16 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_17 = 17 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_18 = 18 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_19 = 19 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_20 = 20 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_21 = 21 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_22 = 22 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_23 = 23 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_24 = 24 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_25 = 25 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_26 = 26 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_27 = 27 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_28 = 28 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_29 = 29 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_30 = 30 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_31 = 31 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_32 = 32 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_33 = 33 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_34 = 34 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_35 = 35 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_36 = 36 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_37 = 37 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_38 = 38 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_39 = 39 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_40 = 40 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_41 = 41 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_42 = 42 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_43 = 43 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_44 = 44 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_45 = 45 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_46 = 46 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_47 = 47 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_48 = 48 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_49 = 49 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_50 = 50 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_51 = 51 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_52 = 52 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_53 = 53 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_54 = 54 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_55 = 55 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_56 = 56 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_57 = 57 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_58 = 58 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_59 = 59 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_60 = 60 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_61 = 61 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_62 = 62 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_63 = 63 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_64 = 64 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_65 = 65 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_66 = 66 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_67 = 67 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_68 = 68 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_69 = 69 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_70 = 70 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_71 = 71 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_72 = 72 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_73 = 73 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_74 = 74 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_75 = 75 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_76 = 76 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_77 = 77 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_78 = 78 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_79 = 79 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_80 = 80 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_81 = 81 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_82 = 82 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_83 = 83 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_84 = 84 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_85 = 85 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_86 = 86 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_87 = 87 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_88 = 88 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_89 = 89 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_90 = 90 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_91 = 91 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_92 = 92 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_93 = 93 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_94 = 94 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_95 = 95 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_96 = 96 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_97 = 97 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_98 = 98 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_99 = 99 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_100 = 100 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_101 = 101 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_102 = 102 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_103 = 103 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_104 = 104 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_105 = 105 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_106 = 106 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_107 = 107 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_108 = 108 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_109 = 109 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_110 = 110 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_111 = 111 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_112 = 112 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_113 = 113 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_114 = 114 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_115 = 115 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_116 = 116 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_117 = 117 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_118 = 118 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_119 = 119 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_120 = 120 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_121 = 121 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_122 = 122 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_123 = 123 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_124 = 124 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_125 = 125 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_126 = 126 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_127 = 127 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_128 = 128 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_129 = 129 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_130 = 130 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_131 = 131 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_132 = 132 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_133 = 133 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_134 = 134 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_135 = 135 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_136 = 136 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_137 = 137 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_138 = 138 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_139 = 139 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_140 = 140 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_141 = 141 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_142 = 142 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_143 = 143 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_144 = 144 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_145 = 145 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_146 = 146 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_147 = 147 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_148 = 148 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_149 = 149 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_150 = 150 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_151 = 151 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_152 = 152 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_153 = 153 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_154 = 154 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_155 = 155 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_156 = 156 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_157 = 157 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_158 = 158 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_159 = 159 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_160 = 160 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_161 = 161 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_162 = 162 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_163 = 163 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_164 = 164 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_165 = 165 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_166 = 166 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_167 = 167 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_168 = 168 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_169 = 169 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_170 = 170 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_171 = 171 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_172 = 172 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_173 = 173 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_174 = 174 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_175 = 175 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_176 = 176 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_177 = 177 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_178 = 178 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_179 = 179 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_180 = 180 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_181 = 181 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_182 = 182 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_183 = 183 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_184 = 184 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_185 = 185 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_186 = 186 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_187 = 187 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_188 = 188 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_189 = 189 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_190 = 190 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_191 = 191 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_192 = 192 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_193 = 193 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_194 = 194 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_195 = 195 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_196 = 196 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_197 = 197 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_198 = 198 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_199 = 199 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_200 = 200 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_201 = 201 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_202 = 202 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_203 = 203 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_204 = 204 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_205 = 205 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_206 = 206 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_207 = 207 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_208 = 208 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_209 = 209 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_210 = 210 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_211 = 211 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_212 = 212 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_213 = 213 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_214 = 214 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_215 = 215 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_216 = 216 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_217 = 217 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_218 = 218 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_219 = 219 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_220 = 220 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_221 = 221 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_222 = 222 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_223 = 223 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_224 = 224 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_225 = 225 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_226 = 226 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_227 = 227 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_228 = 228 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_229 = 229 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_230 = 230 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_231 = 231 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_232 = 232 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_233 = 233 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_234 = 234 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_235 = 235 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_236 = 236 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_237 = 237 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_238 = 238 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_239 = 239 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_240 = 240 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_241 = 241 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_242 = 242 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_243 = 243 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_244 = 244 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_245 = 245 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_246 = 246 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_247 = 247 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_248 = 248 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_249 = 249 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_250 = 250 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_251 = 251 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_252 = 252 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_253 = 253 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_254 = 254 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_255 = 255 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_256 = 256 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_257 = 257 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_258 = 258 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_259 = 259 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_260 = 260 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_261 = 261 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_262 = 262 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_263 = 263 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_264 = 264 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_265 = 265 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_266 = 266 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_267 = 267 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_268 = 268 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_269 = 269 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_270 = 270 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_271 = 271 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_272 = 272 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_273 = 273 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_274 = 274 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_275 = 275 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_276 = 276 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_277 = 277 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_278 = 278 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_279 = 279 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_280 = 280 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_281 = 281 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_282 = 282 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_283 = 283 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_284 = 284 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_285 = 285 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_286 = 286 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_287 = 287 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_288 = 288 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_289 = 289 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_290 = 290 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_291 = 291 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_292 = 292 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_293 = 293 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_294 = 294 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_295 = 295 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_296 = 296 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_297 = 297 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_298 = 298 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_299 = 299 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_300 = 300 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_301 = 301 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_302 = 302 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_303 = 303 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_304 = 304 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_305 = 305 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_306 = 306 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_307 = 307 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_308 = 308 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_309 = 309 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_310 = 310 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_311 = 311 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_312 = 312 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_313 = 313 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_314 = 314 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_315 = 315 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_316 = 316 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_317 = 317 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_318 = 318 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_319 = 319 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_320 = 320 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_321 = 321 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_322 = 322 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_323 = 323 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_324 = 324 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_325 = 325 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_326 = 326 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_327 = 327 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_328 = 328 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_329 = 329 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_330 = 330 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_331 = 331 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_332 = 332 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_333 = 333 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_334 = 334 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_335 = 335 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_336 = 336 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_337 = 337 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_338 = 338 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_339 = 339 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_340 = 340 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_341 = 341 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_342 = 342 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_343 = 343 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_344 = 344 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_345 = 345 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_346 = 346 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_347 = 347 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_348 = 348 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_349 = 349 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_350 = 350 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_351 = 351 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_352 = 352 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_353 = 353 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_354 = 354 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_355 = 355 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_356 = 356 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_357 = 357 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_358 = 358 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_359 = 359 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_360 = 360 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_361 = 361 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_362 = 362 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_363 = 363 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_364 = 364 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_365 = 365 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_366 = 366 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_367 = 367 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_368 = 368 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_369 = 369 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_370 = 370 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_371 = 371 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_372 = 372 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_373 = 373 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_374 = 374 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_375 = 375 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_376 = 376 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_377 = 377 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_378 = 378 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_379 = 379 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_380 = 380 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_381 = 381 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_382 = 382 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_383 = 383 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_384 = 384 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_385 = 385 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_386 = 386 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_387 = 387 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_388 = 388 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_389 = 389 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_390 = 390 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_391 = 391 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_392 = 392 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_393 = 393 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_394 = 394 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_395 = 395 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_396 = 396 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_397 = 397 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_398 = 398 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_399 = 399 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_400 = 400 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_401 = 401 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_402 = 402 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_403 = 403 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_404 = 404 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_405 = 405 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_406 = 406 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_407 = 407 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_408 = 408 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_409 = 409 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_410 = 410 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_411 = 411 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_412 = 412 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_413 = 413 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_414 = 414 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_415 = 415 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_416 = 416 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_417 = 417 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_418 = 418 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_419 = 419 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_420 = 420 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_421 = 421 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_422 = 422 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_423 = 423 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_424 = 424 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_425 = 425 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_426 = 426 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_427 = 427 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_428 = 428 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_429 = 429 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_430 = 430 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_431 = 431 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_432 = 432 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_433 = 433 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_434 = 434 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_435 = 435 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_436 = 436 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_437 = 437 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_438 = 438 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_439 = 439 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_440 = 440 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_441 = 441 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_442 = 442 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_443 = 443 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_444 = 444 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_445 = 445 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_446 = 446 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_447 = 447 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_448 = 448 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_449 = 449 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_450 = 450 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_451 = 451 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_452 = 452 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_453 = 453 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_454 = 454 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_455 = 455 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_456 = 456 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_457 = 457 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_458 = 458 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_459 = 459 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_460 = 460 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_461 = 461 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_462 = 462 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_463 = 463 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_464 = 464 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_465 = 465 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_466 = 466 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_467 = 467 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_468 = 468 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_469 = 469 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_470 = 470 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_471 = 471 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_472 = 472 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_473 = 473 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_474 = 474 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_475 = 475 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_476 = 476 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_477 = 477 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_478 = 478 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_479 = 479 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_480 = 480 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_481 = 481 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_482 = 482 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_483 = 483 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_484 = 484 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_485 = 485 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_486 = 486 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_487 = 487 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_488 = 488 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_489 = 489 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_490 = 490 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_491 = 491 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_492 = 492 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_493 = 493 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_494 = 494 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_495 = 495 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_496 = 496 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_497 = 497 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_498 = 498 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_499 = 499 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_500 = 500 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_501 = 501 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_502 = 502 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_503 = 503 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_504 = 504 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_505 = 505 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_506 = 506 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_507 = 507 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_508 = 508 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_509 = 509 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_510 = 510 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_511 = 511 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_512 = 512 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_513 = 513 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_514 = 514 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_515 = 515 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_516 = 516 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_517 = 517 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_518 = 518 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_519 = 519 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_520 = 520 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_521 = 521 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_522 = 522 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_523 = 523 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_524 = 524 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_525 = 525 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_526 = 526 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_527 = 527 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_528 = 528 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_529 = 529 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_530 = 530 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_531 = 531 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_532 = 532 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_533 = 533 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_534 = 534 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_535 = 535 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_536 = 536 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_537 = 537 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_538 = 538 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_539 = 539 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_540 = 540 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_541 = 541 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_542 = 542 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_543 = 543 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_544 = 544 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_545 = 545 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_546 = 546 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_547 = 547 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_548 = 548 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_549 = 549 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_550 = 550 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_551 = 551 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_552 = 552 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_553 = 553 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_554 = 554 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_555 = 555 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_556 = 556 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_557 = 557 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_558 = 558 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_559 = 559 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_560 = 560 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_561 = 561 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_562 = 562 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_563 = 563 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_564 = 564 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_565 = 565 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_566 = 566 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_567 = 567 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_568 = 568 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_569 = 569 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_570 = 570 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_571 = 571 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_572 = 572 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_573 = 573 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_574 = 574 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_575 = 575 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_576 = 576 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_577 = 577 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_578 = 578 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_579 = 579 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_580 = 580 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_581 = 581 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_582 = 582 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_583 = 583 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_584 = 584 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_585 = 585 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_586 = 586 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_587 = 587 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_588 = 588 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_589 = 589 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_590 = 590 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_591 = 591 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_592 = 592 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_593 = 593 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_594 = 594 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_595 = 595 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_596 = 596 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_597 = 597 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_598 = 598 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_599 = 599 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_600 = 600 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_601 = 601 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_602 = 602 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_603 = 603 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_604 = 604 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_605 = 605 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_606 = 606 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_607 = 607 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_608 = 608 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_609 = 609 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_610 = 610 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_611 = 611 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_612 = 612 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_613 = 613 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_614 = 614 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_615 = 615 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_616 = 616 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_617 = 617 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_618 = 618 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_619 = 619 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_620 = 620 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_621 = 621 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_622 = 622 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_623 = 623 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_624 = 624 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_625 = 625 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_626 = 626 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_627 = 627 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_628 = 628 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_629 = 629 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_630 = 630 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_631 = 631 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_632 = 632 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_633 = 633 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_634 = 634 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_635 = 635 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_636 = 636 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_637 = 637 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_638 = 638 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_639 = 639 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_640 = 640 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_641 = 641 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_642 = 642 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_643 = 643 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_644 = 644 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_645 = 645 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_646 = 646 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_647 = 647 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_648 = 648 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_649 = 649 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_650 = 650 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_651 = 651 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_652 = 652 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_653 = 653 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_654 = 654 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_655 = 655 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_656 = 656 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_657 = 657 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_658 = 658 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_659 = 659 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_660 = 660 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_661 = 661 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_662 = 662 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_663 = 663 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_664 = 664 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_665 = 665 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_666 = 666 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_667 = 667 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_668 = 668 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_669 = 669 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_670 = 670 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_671 = 671 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_672 = 672 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_673 = 673 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_674 = 674 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_675 = 675 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_676 = 676 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_677 = 677 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_678 = 678 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_679 = 679 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_680 = 680 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_681 = 681 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_682 = 682 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_683 = 683 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_684 = 684 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_685 = 685 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_686 = 686 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_687 = 687 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_688 = 688 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_689 = 689 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_690 = 690 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_691 = 691 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_692 = 692 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_693 = 693 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_694 = 694 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_695 = 695 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_696 = 696 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_697 = 697 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_698 = 698 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_699 = 699 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_700 = 700 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_701 = 701 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_702 = 702 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_703 = 703 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_704 = 704 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_705 = 705 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_706 = 706 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_707 = 707 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_708 = 708 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_709 = 709 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_710 = 710 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_711 = 711 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_712 = 712 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_713 = 713 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_714 = 714 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_715 = 715 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_716 = 716 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_717 = 717 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_718 = 718 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_719 = 719 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_720 = 720 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_721 = 721 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_722 = 722 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_723 = 723 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_724 = 724 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_725 = 725 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_726 = 726 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_727 = 727 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_728 = 728 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_729 = 729 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_730 = 730 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_731 = 731 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_732 = 732 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_733 = 733 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_734 = 734 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_735 = 735 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_736 = 736 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_737 = 737 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_738 = 738 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_739 = 739 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_740 = 740 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_741 = 741 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_742 = 742 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_743 = 743 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_744 = 744 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_745 = 745 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_746 = 746 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_747 = 747 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_748 = 748 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_749 = 749 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_750 = 750 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_751 = 751 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_752 = 752 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_753 = 753 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_754 = 754 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_755 = 755 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_756 = 756 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_757 = 757 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_758 = 758 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_759 = 759 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_760 = 760 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_761 = 761 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_762 = 762 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_763 = 763 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_764 = 764 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_765 = 765 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_766 = 766 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_767 = 767 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_768 = 768 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_769 = 769 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_770 = 770 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_771 = 771 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_772 = 772 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_773 = 773 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_774 = 774 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_775 = 775 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_776 = 776 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_777 = 777 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_778 = 778 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_779 = 779 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_780 = 780 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_781 = 781 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_782 = 782 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_783 = 783 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_784 = 784 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_785 = 785 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_786 = 786 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_787 = 787 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_788 = 788 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_789 = 789 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_790 = 790 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_791 = 791 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_792 = 792 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_793 = 793 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_794 = 794 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_795 = 795 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_796 = 796 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_797 = 797 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_798 = 798 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_799 = 799 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_800 = 800 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_801 = 801 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_802 = 802 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_803 = 803 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_804 = 804 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_805 = 805 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_806 = 806 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_807 = 807 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_808 = 808 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_809 = 809 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_810 = 810 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_811 = 811 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_812 = 812 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_813 = 813 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_814 = 814 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_815 = 815 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_816 = 816 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_817 = 817 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_818 = 818 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_819 = 819 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_820 = 820 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_821 = 821 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_822 = 822 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_823 = 823 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_824 = 824 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_825 = 825 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_826 = 826 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_827 = 827 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_828 = 828 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_829 = 829 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_830 = 830 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_831 = 831 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_832 = 832 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_833 = 833 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_834 = 834 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_835 = 835 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_836 = 836 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_837 = 837 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_838 = 838 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_839 = 839 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_840 = 840 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_841 = 841 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_842 = 842 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_843 = 843 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_844 = 844 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_845 = 845 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_846 = 846 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_847 = 847 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_848 = 848 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_849 = 849 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_850 = 850 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_851 = 851 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_852 = 852 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_853 = 853 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_854 = 854 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_855 = 855 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_856 = 856 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_857 = 857 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_858 = 858 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_859 = 859 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_860 = 860 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_861 = 861 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_862 = 862 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_863 = 863 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_864 = 864 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_865 = 865 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_866 = 866 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_867 = 867 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_868 = 868 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_869 = 869 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_870 = 870 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_871 = 871 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_872 = 872 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_873 = 873 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_874 = 874 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_875 = 875 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_876 = 876 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_877 = 877 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_878 = 878 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_879 = 879 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_880 = 880 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_881 = 881 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_882 = 882 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_883 = 883 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_884 = 884 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_885 = 885 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_886 = 886 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_887 = 887 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_888 = 888 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_889 = 889 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_890 = 890 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_891 = 891 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_892 = 892 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_893 = 893 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_894 = 894 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_895 = 895 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_896 = 896 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_897 = 897 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_898 = 898 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_899 = 899 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_900 = 900 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_901 = 901 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_902 = 902 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_903 = 903 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_904 = 904 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_905 = 905 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_906 = 906 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_907 = 907 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_908 = 908 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_909 = 909 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_910 = 910 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_911 = 911 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_912 = 912 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_913 = 913 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_914 = 914 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_915 = 915 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_916 = 916 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_917 = 917 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_918 = 918 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_919 = 919 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_920 = 920 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_921 = 921 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_922 = 922 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_923 = 923 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_924 = 924 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_925 = 925 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_926 = 926 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_927 = 927 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_928 = 928 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_929 = 929 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_930 = 930 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_931 = 931 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_932 = 932 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_933 = 933 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_934 = 934 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_935 = 935 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_936 = 936 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_937 = 937 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_938 = 938 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_939 = 939 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_940 = 940 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_941 = 941 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_942 = 942 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_943 = 943 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_944 = 944 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_945 = 945 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_946 = 946 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_947 = 947 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_948 = 948 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_949 = 949 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_950 = 950 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_951 = 951 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_952 = 952 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_953 = 953 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_954 = 954 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_955 = 955 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_956 = 956 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_957 = 957 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_958 = 958 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_959 = 959 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_960 = 960 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_961 = 961 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_962 = 962 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_963 = 963 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_964 = 964 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_965 = 965 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_966 = 966 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_967 = 967 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_968 = 968 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_969 = 969 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_970 = 970 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_971 = 971 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_972 = 972 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_973 = 973 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_974 = 974 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_975 = 975 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_976 = 976 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_977 = 977 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_978 = 978 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_979 = 979 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_980 = 980 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_981 = 981 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_982 = 982 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_983 = 983 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_984 = 984 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_985 = 985 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_986 = 986 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_987 = 987 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_988 = 988 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_989 = 989 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_990 = 990 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_991 = 991 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_992 = 992 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_993 = 993 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_994 = 994 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_995 = 995 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_996 = 996 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_997 = 997 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_998 = 998 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_999 = 999 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+  optional string long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000 = 1000 [default="long default value is also loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"];
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import.proto
new file mode 100644
index 0000000..c115b11
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import.proto
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which is imported by unittest.proto to test importing.
+
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do
+// "using namespace unittest_import = protobuf_unittest_import".
+package protobuf_unittest_import;
+
+option optimize_for = SPEED;
+
+// Excercise the java_package option.
+option java_package = "com.google.protobuf.test";
+
+// Do not set a java_outer_classname here to verify that Proto2 works without
+// one.
+
+// Test public import
+import public "google/protobuf/unittest_import_public.proto";
+
+message ImportMessage {
+  optional int32 d = 1;
+}
+
+enum ImportEnum {
+  IMPORT_FOO = 7;
+  IMPORT_BAR = 8;
+  IMPORT_BAZ = 9;
+}
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_lite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_lite.proto
new file mode 100644
index 0000000..81b117f
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_lite.proto
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest_import.proto but with optimize_for = LITE_RUNTIME.
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+import public "google/protobuf/unittest_import_public_lite.proto";
+
+message ImportMessageLite {
+  optional int32 d = 1;
+}
+
+enum ImportEnumLite {
+  IMPORT_LITE_FOO = 7;
+  IMPORT_LITE_BAR = 8;
+  IMPORT_LITE_BAZ = 9;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public.proto
new file mode 100644
index 0000000..ea5d1b1
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+
+message PublicImportMessage {
+  optional int32 e = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public_lite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public_lite.proto
new file mode 100644
index 0000000..d077563
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_import_public_lite.proto
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+
+package protobuf_unittest_import;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+message PublicImportMessageLite {
+  optional int32 e = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite.proto
new file mode 100644
index 0000000..a1764aa
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite.proto
@@ -0,0 +1,360 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest.proto but with optimize_for = LITE_RUNTIME.
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest_import_lite.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "com.google.protobuf";
+
+// Same as TestAllTypes but with the lite runtime.
+message TestAllTypesLite {
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+  optional ForeignMessageLite optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessageLite
+    optional_import_message = 20;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+  optional ForeignEnumLite optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnumLite optional_import_enum = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessageLite
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+  repeated ForeignMessageLite repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessageLite
+    repeated_import_message = 50;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+  repeated ForeignEnumLite repeated_foreign_enum = 52;
+  repeated protobuf_unittest_import.ImportEnumLite repeated_import_enum = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+  optional ForeignEnumLite default_foreign_enum = 82
+      [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite
+      default_import_enum = 83 [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+}
+
+message ForeignMessageLite {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumLite {
+  FOREIGN_LITE_FOO = 4;
+  FOREIGN_LITE_BAR = 5;
+  FOREIGN_LITE_BAZ = 6;
+}
+
+message TestPackedTypesLite {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnumLite packed_enum  = 103 [packed = true];
+}
+
+message TestAllExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestAllExtensionsLite {
+  // Singular
+  optional    int32 optional_int32_extension_lite    =  1;
+  optional    int64 optional_int64_extension_lite    =  2;
+  optional   uint32 optional_uint32_extension_lite   =  3;
+  optional   uint64 optional_uint64_extension_lite   =  4;
+  optional   sint32 optional_sint32_extension_lite   =  5;
+  optional   sint64 optional_sint64_extension_lite   =  6;
+  optional  fixed32 optional_fixed32_extension_lite  =  7;
+  optional  fixed64 optional_fixed64_extension_lite  =  8;
+  optional sfixed32 optional_sfixed32_extension_lite =  9;
+  optional sfixed64 optional_sfixed64_extension_lite = 10;
+  optional    float optional_float_extension_lite    = 11;
+  optional   double optional_double_extension_lite   = 12;
+  optional     bool optional_bool_extension_lite     = 13;
+  optional   string optional_string_extension_lite   = 14;
+  optional    bytes optional_bytes_extension_lite    = 15;
+
+  optional group OptionalGroup_extension_lite = 16 {
+    optional int32 a = 17;
+  }
+
+  optional TestAllTypesLite.NestedMessage optional_nested_message_extension_lite
+      = 18;
+  optional ForeignMessageLite optional_foreign_message_extension_lite = 19;
+  optional protobuf_unittest_import.ImportMessageLite
+    optional_import_message_extension_lite = 20;
+
+  optional TestAllTypesLite.NestedEnum optional_nested_enum_extension_lite = 21;
+  optional ForeignEnumLite optional_foreign_enum_extension_lite = 22;
+  optional protobuf_unittest_import.ImportEnumLite
+    optional_import_enum_extension_lite = 23;
+
+  optional string optional_string_piece_extension_lite = 24
+      [ctype=STRING_PIECE];
+  optional string optional_cord_extension_lite = 25 [ctype=CORD];
+
+  optional protobuf_unittest_import.PublicImportMessageLite
+    optional_public_import_message_extension_lite = 26;
+
+  optional TestAllTypesLite.NestedMessage
+    optional_lazy_message_extension_lite = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32_extension_lite    = 31;
+  repeated    int64 repeated_int64_extension_lite    = 32;
+  repeated   uint32 repeated_uint32_extension_lite   = 33;
+  repeated   uint64 repeated_uint64_extension_lite   = 34;
+  repeated   sint32 repeated_sint32_extension_lite   = 35;
+  repeated   sint64 repeated_sint64_extension_lite   = 36;
+  repeated  fixed32 repeated_fixed32_extension_lite  = 37;
+  repeated  fixed64 repeated_fixed64_extension_lite  = 38;
+  repeated sfixed32 repeated_sfixed32_extension_lite = 39;
+  repeated sfixed64 repeated_sfixed64_extension_lite = 40;
+  repeated    float repeated_float_extension_lite    = 41;
+  repeated   double repeated_double_extension_lite   = 42;
+  repeated     bool repeated_bool_extension_lite     = 43;
+  repeated   string repeated_string_extension_lite   = 44;
+  repeated    bytes repeated_bytes_extension_lite    = 45;
+
+  repeated group RepeatedGroup_extension_lite = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated TestAllTypesLite.NestedMessage repeated_nested_message_extension_lite
+      = 48;
+  repeated ForeignMessageLite repeated_foreign_message_extension_lite = 49;
+  repeated protobuf_unittest_import.ImportMessageLite
+    repeated_import_message_extension_lite = 50;
+
+  repeated TestAllTypesLite.NestedEnum repeated_nested_enum_extension_lite = 51;
+  repeated ForeignEnumLite repeated_foreign_enum_extension_lite = 52;
+  repeated protobuf_unittest_import.ImportEnumLite
+    repeated_import_enum_extension_lite = 53;
+
+  repeated string repeated_string_piece_extension_lite = 54
+      [ctype=STRING_PIECE];
+  repeated string repeated_cord_extension_lite = 55 [ctype=CORD];
+
+  repeated TestAllTypesLite.NestedMessage
+    repeated_lazy_message_extension_lite = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32_extension_lite    = 61 [default =  41    ];
+  optional    int64 default_int64_extension_lite    = 62 [default =  42    ];
+  optional   uint32 default_uint32_extension_lite   = 63 [default =  43    ];
+  optional   uint64 default_uint64_extension_lite   = 64 [default =  44    ];
+  optional   sint32 default_sint32_extension_lite   = 65 [default = -45    ];
+  optional   sint64 default_sint64_extension_lite   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32_extension_lite  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64_extension_lite  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32_extension_lite = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64_extension_lite = 70 [default = -50    ];
+  optional    float default_float_extension_lite    = 71 [default =  51.5  ];
+  optional   double default_double_extension_lite   = 72 [default =  52e3  ];
+  optional     bool default_bool_extension_lite     = 73 [default = true   ];
+  optional   string default_string_extension_lite   = 74 [default = "hello"];
+  optional    bytes default_bytes_extension_lite    = 75 [default = "world"];
+
+  optional TestAllTypesLite.NestedEnum
+    default_nested_enum_extension_lite = 81 [default = BAR];
+  optional ForeignEnumLite
+    default_foreign_enum_extension_lite = 82 [default = FOREIGN_LITE_BAR];
+  optional protobuf_unittest_import.ImportEnumLite
+    default_import_enum_extension_lite = 83 [default = IMPORT_LITE_BAR];
+
+  optional string default_string_piece_extension_lite = 84 [ctype=STRING_PIECE,
+                                                            default="abc"];
+  optional string default_cord_extension_lite = 85 [ctype=CORD, default="123"];
+}
+
+message TestPackedExtensionsLite {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensionsLite {
+  repeated    int32 packed_int32_extension_lite    =  90 [packed = true];
+  repeated    int64 packed_int64_extension_lite    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension_lite   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension_lite   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension_lite   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension_lite   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension_lite  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension_lite  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension_lite =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension_lite =  99 [packed = true];
+  repeated    float packed_float_extension_lite    = 100 [packed = true];
+  repeated   double packed_double_extension_lite   = 101 [packed = true];
+  repeated     bool packed_bool_extension_lite     = 102 [packed = true];
+  repeated ForeignEnumLite packed_enum_extension_lite = 103 [packed = true];
+}
+
+message TestNestedExtensionLite {
+  extend TestAllExtensionsLite {
+    optional int32 nested_extension = 12345;
+  }
+}
+
+// Test that deprecated fields work.  We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedLite {
+  optional int32 deprecated_field = 1 [deprecated = true];
+}
+
+// See the comments of the same type in unittest.proto.
+message TestParsingMergeLite {
+  message RepeatedFieldsGenerator {
+    repeated TestAllTypesLite field1 = 1;
+    repeated TestAllTypesLite field2 = 2;
+    repeated TestAllTypesLite field3 = 3;
+    repeated group Group1 = 10 {
+      optional TestAllTypesLite field1 = 11;
+    }
+    repeated group Group2 = 20 {
+      optional TestAllTypesLite field1 = 21;
+    }
+    repeated TestAllTypesLite ext1 = 1000;
+    repeated TestAllTypesLite ext2 = 1001;
+  }
+  required TestAllTypesLite required_all_types = 1;
+  optional TestAllTypesLite optional_all_types = 2;
+  repeated TestAllTypesLite repeated_all_types = 3;
+  optional group OptionalGroup = 10 {
+    optional TestAllTypesLite optional_group_all_types = 11;
+  }
+  repeated group RepeatedGroup = 20 {
+    optional TestAllTypesLite repeated_group_all_types = 21;
+  }
+  extensions 1000 to max;
+  extend TestParsingMergeLite {
+    optional TestAllTypesLite optional_ext = 1000;
+    repeated TestAllTypesLite repeated_ext = 1001;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto
new file mode 100644
index 0000000..d52cb8c
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_lite_imports_nonlite.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// Tests that a "lite" message can import a regular message.
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+message TestLiteImportsNonlite {
+  optional TestAllTypes message = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_mset.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_mset.proto
new file mode 100644
index 0000000..3497f09
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_mset.proto
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains messages for testing message_set_wire_format.
+
+package protobuf_unittest;
+
+option optimize_for = SPEED;
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message TestMessageSetContainer {
+  optional TestMessageSet message_set = 1;
+}
+
+message TestMessageSetExtension1 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension1 message_set_extension = 1545008;
+  }
+  optional int32 i = 15;
+}
+
+message TestMessageSetExtension2 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension2 message_set_extension = 1547769;
+  }
+  optional string str = 25;
+}
+
+// MessageSet wire format is equivalent to this.
+message RawMessageSet {
+  repeated group Item = 1 {
+    required int32 type_id = 2;
+    required bytes message = 3;
+  }
+}
+
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_no_generic_services.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_no_generic_services.proto
new file mode 100644
index 0000000..cffb412
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_no_generic_services.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+package google.protobuf.no_generic_services_test;
+
+// *_generic_services are false by default.
+
+message TestMessage {
+  optional int32 a = 1;
+  extensions 1000 to max;
+}
+
+enum TestEnum {
+  FOO = 1;
+}
+
+extend TestMessage {
+  optional int32 test_extension = 1000;
+}
+
+service TestService {
+  rpc Foo(TestMessage) returns(TestMessage);
+}
diff --git a/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_optimize_for.proto b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_optimize_for.proto
new file mode 100644
index 0000000..feecbef
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/protos/src/proto/google/protobuf/unittest_optimize_for.proto
@@ -0,0 +1,61 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which uses optimize_for = CODE_SIZE.
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option optimize_for = CODE_SIZE;
+
+message TestOptimizedForSize {
+  optional int32 i = 1;
+  optional ForeignMessage msg = 19;
+
+  extensions 1000 to max;
+
+  extend TestOptimizedForSize {
+    optional int32 test_extension = 1234;
+    optional TestRequiredOptimizedForSize test_extension2 = 1235;
+  }
+}
+
+message TestRequiredOptimizedForSize {
+  required int32 x = 1;
+}
+ 
+message TestOptionalOptimizedForSize {
+  optional TestRequiredOptimizedForSize o = 1;
+}
diff --git a/java/compatibility_tests/v2.5.0/test.sh b/java/compatibility_tests/v2.5.0/test.sh
new file mode 100755
index 0000000..5d5e9ed
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/test.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+
+set -ex
+
+# Change to the script's directory.
+cd $(dirname $0)
+
+# Version of the tests (i.e., the version of protobuf from where we extracted
+# these tests).
+TEST_VERSION=`grep "^  <version>.*</version>" pom.xml | sed "s|  <version>\(.*\)</version>|\1|"`
+
+# The old version of protobuf that we are testing compatibility against. This
+# is usually the same as TEST_VERSION (i.e., we use the tests extracted from
+# that version to test compatibility of the newest runtime against it), but it
+# is also possible to use this same test set to test the compatibiilty of the
+# latest version against other versions.
+case "$1" in
+  ""|2.5.0)
+    OLD_VERSION=2.5.0
+    OLD_VERSION_PROTOC=https://github.com/xfxyjwf/protobuf-compiler-release/raw/master/v2.5.0/linux/protoc
+    ;;
+  2.6.1)
+    OLD_VERSION=2.6.1
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/2.6.1-build2/protoc-2.6.1-build2-linux-x86_64.exe
+    ;;
+  3.0.0-beta-1)
+    OLD_VERSION=3.0.0-beta-1
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-1/protoc-3.0.0-beta-1-linux-x86_64.exe
+    ;;
+  3.0.0-beta-2)
+    OLD_VERSION=3.0.0-beta-2
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-2/protoc-3.0.0-beta-2-linux-x86_64.exe
+    ;;
+  3.0.0-beta-3)
+    OLD_VERSION=3.0.0-beta-3
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-3/protoc-3.0.0-beta-3-linux-x86_64.exe
+    ;;
+  3.0.0-beta-4)
+    OLD_VERSION=3.0.0-beta-4
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-4/protoc-3.0.0-beta-4-linux-x86_64.exe
+    ;;
+  *)
+    echo "[ERROR]: Unknown version number: $1"
+    exit 1
+    ;;
+esac
+
+# Extract the latest protobuf version number.
+VERSION_NUMBER=`grep "^  <version>.*</version>" ../../pom.xml | sed "s|  <version>\(.*\)</version>|\1|"`
+
+echo "Running compatibility tests between $VERSION_NUMBER and $OLD_VERSION"
+
+# Check protoc
+[ -f ../../../src/protoc ] || {
+  echo "[ERROR]: Please build protoc first."
+  exit 1
+}
+
+# Build and install protobuf-java-$VERSION_NUMBER.jar
+[ -f ../../core/target/protobuf-java-$VERSION_NUMBER.jar ] || {
+  pushd ../..
+  mvn install -Dmaven.test.skip=true
+  popd
+}
+
+# Download old version source for the compatibility test
+[ -d protobuf ] || {
+  git clone https://github.com/google/protobuf.git
+  cd protobuf
+  git reset --hard v$TEST_VERSION
+  cd ..
+}
+
+# Download old version protoc compiler (for linux)
+wget $OLD_VERSION_PROTOC -O protoc
+chmod +x protoc
+
+# Test source compatibility. In these tests we recompile everything against
+# the new runtime (including old version generated code).
+
+# Test A.1:
+#   protos: use new version
+#   more_protos: use old version
+mvn clean test \
+  -Dprotobuf.test.source.path=$(pwd)/protobuf \
+  -Dprotoc.path=$(pwd)/protoc \
+  -Dprotos.protoc.path=$(pwd)/../../../src/protoc \
+  -Dprotobuf.version=$VERSION_NUMBER
+
+# Test A.2:
+#   protos: use old version
+#   more_protos: use new version
+mvn clean test \
+  -Dprotobuf.test.source.path=$(pwd)/protobuf \
+  -Dprotoc.path=$(pwd)/protoc \
+  -Dmore_protos.protoc.path=$(pwd)/../../../src/protoc \
+  -Dprotobuf.version=$VERSION_NUMBER
+
+# Test binary compatibility. In these tests we run the old version compiled
+# jar against the new runtime directly without recompile.
+
+# Collect all test dependencies in a single jar file (except for protobuf) to
+# make it easier to run binary compatibility test (where we will need to run
+# the jar files directly).
+cd deps
+mvn assembly:single
+cd ..
+cp -f deps/target/compatibility-test-deps-${TEST_VERSION}-jar-with-dependencies.jar deps.jar
+
+# Build the old version of all 3 artifacts.
+mvn clean install -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/protoc -Dprotobuf.version=$OLD_VERSION
+cp -f protos/target/compatibility-protos-${TEST_VERSION}.jar protos.jar
+cp -f more_protos/target/compatibility-more-protos-${TEST_VERSION}.jar more_protos.jar
+cp -f tests/target/compatibility-tests-${TEST_VERSION}.jar tests.jar
+
+# Collect the list of tests we need to run.
+TESTS=`find tests -name "*Test.java" | sed "s|/|.|g;s/.java$//g;s/tests.src.main.java.//g"`
+
+# Test B.1: run all the old artifacts against the new runtime. Note that we
+# must run the test in the protobuf source tree because some of the tests need
+# to read golden test data files.
+cd protobuf
+java -cp ../../../core/target/protobuf-java-$VERSION_NUMBER.jar:../protos.jar:../more_protos.jar:../tests.jar:../deps.jar org.junit.runner.JUnitCore $TESTS
+cd ..
+
+# Test B.2: update protos.jar only.
+cd protos
+mvn clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
+cd ..
+cd protobuf
+java -cp ../../../core/target/protobuf-java-$VERSION_NUMBER.jar:../protos/target/compatibility-protos-${TEST_VERSION}.jar:../more_protos.jar:../tests.jar:../deps.jar org.junit.runner.JUnitCore $TESTS
+cd ..
+
+# Test B.3: update more_protos.jar only.
+cd more_protos
+mvn clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
+cd ..
+cd protobuf
+java -cp ../../../core/target/protobuf-java-$VERSION_NUMBER.jar:../protos.jar:../more_protos/target/compatibility-more-protos-${TEST_VERSION}.jar:../tests.jar:../deps.jar org.junit.runner.JUnitCore $TESTS
+cd ..
diff --git a/java/compatibility_tests/v2.5.0/tests/pom.xml b/java/compatibility_tests/v2.5.0/tests/pom.xml
new file mode 100644
index 0000000..f1ce46e
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/pom.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf.compatibility</groupId>
+    <artifactId>compatibility-test-suite</artifactId>
+    <version>2.5.0</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>com.google.protobuf.compatibility</groupId>
+  <artifactId>compatibility-tests</artifactId>
+  <version>2.5.0</version>
+
+  <name>Compatibility Tests</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+      <version>2.2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.protobuf</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${tests.protobuf.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.protobuf.compatibility</groupId>
+      <artifactId>compatibility-protos</artifactId>
+      <version>2.5.0</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.protobuf.compatibility</groupId>
+      <artifactId>compatibility-more-protos</artifactId>
+      <version>2.5.0</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.6</source>
+          <target>1.6</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <testSourceDirectory>${basedir}/src/main/java/</testSourceDirectory>
+          <testClassesDirectory>${project.build.directory}/classes/</testClassesDirectory>
+          <includes>
+            <include>**/*Test.java</include>
+          </includes>
+          <workingDirectory>${protobuf.test.source.path}</workingDirectory>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/AbstractMessageTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/AbstractMessageTest.java
new file mode 100644
index 0000000..6789550
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/AbstractMessageTest.java
@@ -0,0 +1,510 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+/**
+ * Unit test for {@link AbstractMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class AbstractMessageTest extends TestCase {
+  /**
+   * 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 object.  This allows us to
+   * test that AbstractMessage's implementations work even if the wrapped
+   * object does not use them.
+   */
+  private static class AbstractMessageWrapper extends AbstractMessage {
+    private final Message wrappedMessage;
+
+    public AbstractMessageWrapper(Message wrappedMessage) {
+      this.wrappedMessage = wrappedMessage;
+    }
+
+    public Descriptors.Descriptor getDescriptorForType() {
+      return wrappedMessage.getDescriptorForType();
+    }
+    public AbstractMessageWrapper getDefaultInstanceForType() {
+      return new AbstractMessageWrapper(
+        wrappedMessage.getDefaultInstanceForType());
+    }
+    public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+      return wrappedMessage.getAllFields();
+    }
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.hasField(field);
+    }
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.getField(field);
+    }
+    public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.getRepeatedFieldCount(field);
+    }
+    public Object getRepeatedField(
+        Descriptors.FieldDescriptor field, int index) {
+      return wrappedMessage.getRepeatedField(field, index);
+    }
+    public UnknownFieldSet getUnknownFields() {
+      return wrappedMessage.getUnknownFields();
+    }
+    public Builder newBuilderForType() {
+      return new Builder(wrappedMessage.newBuilderForType());
+    }
+    public Builder toBuilder() {
+      return new Builder(wrappedMessage.toBuilder());
+    }
+
+    static class Builder extends AbstractMessage.Builder<Builder> {
+      private final Message.Builder wrappedBuilder;
+
+      public Builder(Message.Builder wrappedBuilder) {
+        this.wrappedBuilder = wrappedBuilder;
+      }
+
+      public AbstractMessageWrapper build() {
+        return new AbstractMessageWrapper(wrappedBuilder.build());
+      }
+      public AbstractMessageWrapper buildPartial() {
+        return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
+      }
+      public Builder clone() {
+        return new Builder(wrappedBuilder.clone());
+      }
+      public boolean isInitialized() {
+        return clone().buildPartial().isInitialized();
+      }
+      public Descriptors.Descriptor getDescriptorForType() {
+        return wrappedBuilder.getDescriptorForType();
+      }
+      public AbstractMessageWrapper getDefaultInstanceForType() {
+        return new AbstractMessageWrapper(
+          wrappedBuilder.getDefaultInstanceForType());
+      }
+      public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+        return wrappedBuilder.getAllFields();
+      }
+      public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
+        return new Builder(wrappedBuilder.newBuilderForField(field));
+      }
+      public boolean hasField(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.hasField(field);
+      }
+      public Object getField(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.getField(field);
+      }
+      public Builder setField(Descriptors.FieldDescriptor field, Object value) {
+        wrappedBuilder.setField(field, value);
+        return this;
+      }
+      public Builder clearField(Descriptors.FieldDescriptor field) {
+        wrappedBuilder.clearField(field);
+        return this;
+      }
+      public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.getRepeatedFieldCount(field);
+      }
+      public Object getRepeatedField(
+          Descriptors.FieldDescriptor field, int index) {
+        return wrappedBuilder.getRepeatedField(field, index);
+      }
+      public Builder setRepeatedField(Descriptors.FieldDescriptor field,
+                                      int index, Object value) {
+        wrappedBuilder.setRepeatedField(field, index, value);
+        return this;
+      }
+      public Builder addRepeatedField(
+          Descriptors.FieldDescriptor field, Object value) {
+        wrappedBuilder.addRepeatedField(field, value);
+        return this;
+      }
+      public UnknownFieldSet getUnknownFields() {
+        return wrappedBuilder.getUnknownFields();
+      }
+      public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+        wrappedBuilder.setUnknownFields(unknownFields);
+        return this;
+      }
+      @Override
+      public Message.Builder getFieldBuilder(FieldDescriptor field) {
+        return wrappedBuilder.getFieldBuilder(field);
+      }
+    }
+    public Parser<? extends Message> getParserForType() {
+      return wrappedMessage.getParserForType();
+    }
+  }
+
+  // =================================================================
+
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+
+  public void testClear() throws Exception {
+    AbstractMessageWrapper message =
+      new AbstractMessageWrapper.Builder(
+          TestAllTypes.newBuilder(TestUtil.getAllSet()))
+        .clear().build();
+    TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testCopy() throws Exception {
+    AbstractMessageWrapper message =
+      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
+        .mergeFrom(TestUtil.getAllSet()).build();
+    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testSerializedSize() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+    assertEquals(message.getSerializedSize(),
+                 abstractMessage.getSerializedSize());
+  }
+
+  public void testSerialization() throws Exception {
+    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+    TestUtil.assertAllFieldsSet(
+      TestAllTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getAllSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
+    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testParsingUninitialized() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+    builder.getOptionalMessageBuilder().setDummy2(10);
+    ByteString bytes = builder.buildPartial().toByteString();
+    Message.Builder abstractMessageBuilder =
+        new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
+    // mergeFrom() should not throw initialization error.
+    abstractMessageBuilder.mergeFrom(bytes).buildPartial();
+    try {
+      abstractMessageBuilder.mergeFrom(bytes).build();
+      fail();
+    } catch (UninitializedMessageException ex) {
+      // pass
+    }
+
+    // test DynamicMessage directly.
+    Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
+        TestRequiredForeign.getDescriptor());
+    // mergeFrom() should not throw initialization error.
+    dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
+    try {
+      dynamicMessageBuilder.mergeFrom(bytes).build();
+      fail();
+    } catch (UninitializedMessageException ex) {
+      // pass
+    }
+  }
+
+  public void testPackedSerialization() throws Exception {
+    Message abstractMessage =
+        new AbstractMessageWrapper(TestUtil.getPackedSet());
+
+    TestUtil.assertPackedFieldsSet(
+      TestPackedTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getPackedSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testPackedParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
+  }
+
+  public void testUnpackedSerialization() throws Exception {
+    Message abstractMessage =
+      new AbstractMessageWrapper(TestUtil.getUnpackedSet());
+
+    TestUtil.assertUnpackedFieldsSet(
+      TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getUnpackedSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testParsePackedToUnpacked() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(
+      (TestUnpackedTypes) message.wrappedMessage);
+  }
+
+  public void testParseUnpackedToPacked() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
+  }
+
+  public void testUnpackedParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(
+      (TestUnpackedTypes) message.wrappedMessage);
+  }
+
+  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());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for isInitialized().
+
+  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+    TestRequired.getDefaultInstance();
+  private static final TestRequired TEST_REQUIRED_INITIALIZED =
+    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+  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());
+    builder.setA(1);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals("b, c", abstractBuilder.getInitializationErrorString());
+    builder.setB(1);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals("c", abstractBuilder.getInitializationErrorString());
+    builder.setC(1);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+  }
+
+  public void testForeignIsInitialized() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+    AbstractMessageWrapper.Builder abstractBuilder =
+      new AbstractMessageWrapper.Builder(builder);
+
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+
+    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals(
+        "optional_message.a, optional_message.b, optional_message.c",
+        abstractBuilder.getInitializationErrorString());
+
+    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+
+    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals(
+        "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+        abstractBuilder.getInitializationErrorString());
+
+    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for mergeFrom
+
+  static final TestAllTypes MERGE_SOURCE =
+    TestAllTypes.newBuilder()
+      .setOptionalInt32(1)
+      .setOptionalString("foo")
+      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+      .addRepeatedString("bar")
+      .build();
+
+  static final TestAllTypes MERGE_DEST =
+    TestAllTypes.newBuilder()
+      .setOptionalInt64(2)
+      .setOptionalString("baz")
+      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+      .addRepeatedString("qux")
+      .build();
+
+  static final String MERGE_RESULT_TEXT =
+      "optional_int32: 1\n" +
+      "optional_int64: 2\n" +
+      "optional_string: \"foo\"\n" +
+      "optional_foreign_message {\n" +
+      "  c: 3\n" +
+      "}\n" +
+      "repeated_string: \"qux\"\n" +
+      "repeated_string: \"bar\"\n";
+
+  public void testMergeFrom() throws Exception {
+    AbstractMessageWrapper result =
+      new AbstractMessageWrapper.Builder(
+        TestAllTypes.newBuilder(MERGE_DEST))
+      .mergeFrom(MERGE_SOURCE).build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for equals and hashCode
+
+  public void testEqualsAndHashCode() throws Exception {
+    TestAllTypes a = TestUtil.getAllSet();
+    TestAllTypes b = TestAllTypes.newBuilder().build();
+    TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
+    TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
+    TestAllExtensions e = TestUtil.getAllExtensionsSet();
+    TestAllExtensions f = TestAllExtensions.newBuilder(e)
+        .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
+
+    checkEqualsIsConsistent(a);
+    checkEqualsIsConsistent(b);
+    checkEqualsIsConsistent(c);
+    checkEqualsIsConsistent(d);
+    checkEqualsIsConsistent(e);
+    checkEqualsIsConsistent(f);
+
+    checkNotEqual(a, b);
+    checkNotEqual(a, c);
+    checkNotEqual(a, d);
+    checkNotEqual(a, e);
+    checkNotEqual(a, f);
+
+    checkNotEqual(b, c);
+    checkNotEqual(b, d);
+    checkNotEqual(b, e);
+    checkNotEqual(b, f);
+
+    checkNotEqual(c, d);
+    checkNotEqual(c, e);
+    checkNotEqual(c, f);
+
+    checkNotEqual(d, e);
+    checkNotEqual(d, f);
+
+    checkNotEqual(e, f);
+
+    // Deserializing into the TestEmptyMessage such that every field
+    // is an {@link UnknownFieldSet.Field}.
+    UnittestProto.TestEmptyMessage eUnknownFields =
+        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+    UnittestProto.TestEmptyMessage fUnknownFields =
+        UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
+    checkNotEqual(eUnknownFields, fUnknownFields);
+    checkEqualsIsConsistent(eUnknownFields);
+    checkEqualsIsConsistent(fUnknownFields);
+
+    // Subsequent reconstitutions should be identical
+    UnittestProto.TestEmptyMessage eUnknownFields2 =
+        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+    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);
+
+    // Object should be equal to a dynamic copy of itself.
+    DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
+    checkEqualsIsConsistent(message, dynamic);
+  }
+
+  /**
+   * 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());
+  }
+
+  /**
+   * Asserts that the given protos are not equal and have different hash codes.
+   *
+   * @warning It's valid for non-equal objects to have the same hash code, so
+   *   this test is stricter than it needs to be. However, this should happen
+   *   relatively rarely.
+   */
+  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));
+
+    assertFalse(
+        String.format("%s should have a different hash code from %s", m1, m2),
+        m1.hashCode() == m2.hashCode());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/BoundedByteStringTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/BoundedByteStringTest.java
new file mode 100644
index 0000000..c838274
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/BoundedByteStringTest.java
@@ -0,0 +1,56 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * 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 carlanton@google.com (Carl Haverl)
+ */
+public class BoundedByteStringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "BoundedByteString";
+    byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
+    int from = 100;
+    int to = sourceBytes.length - 100;
+    stringUnderTest = ByteString.copyFrom(sourceBytes).substring(from, to);
+    referenceBytes = new byte[to - from];
+    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+    expectedHashCode = 727575887;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ByteStringTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ByteStringTest.java
new file mode 100644
index 0000000..8bb9f73
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ByteStringTest.java
@@ -0,0 +1,590 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.ByteString.Output;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+ * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
+ * tests.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class ByteStringTest extends TestCase {
+
+  private static final String UTF_16 = "UTF-16";
+
+  static byte[] getTestBytes(int size, long seed) {
+    Random random = new Random(seed);
+    byte[] result = new byte[size];
+    random.nextBytes(result);
+    return result;
+  }
+
+  private byte[] getTestBytes(int size) {
+    return getTestBytes(size, 445566L);
+  }
+
+  private byte[] getTestBytes() {
+    return getTestBytes(1000);
+  }
+
+  // Compare the entire left array with a subset of the right array.
+  private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
+    boolean stillEqual = (left.length == length);
+    for (int i = 0; (stillEqual && i < length); ++i) {
+      stillEqual = (left[i] == right[rightOffset + i]);
+    }
+    return stillEqual;
+  }
+
+  // Returns true only if the given two arrays have identical contents.
+  private boolean isArray(byte[] left, byte[] right) {
+    return left.length == right.length && isArrayRange(left, right, 0, left.length);
+  }
+
+  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));
+  }
+
+  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));
+  }
+
+  public void testCopyFrom_Bytes() {
+    byte[] bytes = getTestBytes();
+    ByteString byteString = ByteString.copyFrom(bytes);
+    assertTrue("copyFrom must contain the expected bytes",
+        isArray(byteString.toByteArray(), bytes));
+  }
+
+  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));
+  }
+
+  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));
+  }
+
+  public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
+    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));
+  }
+
+  public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString byteString = ByteString.copyFromUtf8(testString);
+    byte[] testBytes = testString.getBytes("UTF-8");
+    assertTrue("copyFromUtf8 string must respect the charset",
+        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+  }
+
+  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));
+    // Call copyFrom on an iteration that's not a collection
+    ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
+      public Iterator<ByteString> iterator() {
+        return pieces.iterator();
+      }
+    });
+    assertEquals("copyFrom from an Iteration must contain the expected bytes",
+        byteString, byteStringAlt);
+  }
+
+  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));
+  }
+
+  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);
+  }
+
+  public void testReadFrom_smallStream() throws IOException {
+    assertReadFrom(getTestBytes(10));
+  }
+
+  public void testReadFrom_mutating() throws IOException {
+    byte[] capturedArray = null;
+    EvilInputStream eis = new EvilInputStream();
+    ByteString byteString = ByteString.readFrom(eis);
+
+    capturedArray = eis.capturedArray;
+    byte[] originalValue = byteString.toByteArray();
+    for (int x = 0; x < capturedArray.length; ++x) {
+      capturedArray[x] = (byte) 0;
+    }
+
+    byte[] newValue = byteString.toByteArray();
+    assertTrue("copyFrom byteBuffer must not grant access to underlying array",
+        Arrays.equals(originalValue, newValue));
+  }
+
+  // Tests sizes that are over multi-segment rope threshold.
+  public void testReadFrom_largeStream() throws IOException {
+    assertReadFrom(getTestBytes(0x100));
+    assertReadFrom(getTestBytes(0x101));
+    assertReadFrom(getTestBytes(0x110));
+    assertReadFrom(getTestBytes(0x1000));
+    assertReadFrom(getTestBytes(0x1001));
+    assertReadFrom(getTestBytes(0x1010));
+    assertReadFrom(getTestBytes(0x10000));
+    assertReadFrom(getTestBytes(0x10001));
+    assertReadFrom(getTestBytes(0x10010));
+  }
+
+  // Tests that IOExceptions propagate through ByteString.readFrom().
+  public void testReadFrom_IOExceptions() {
+    try {
+      ByteString.readFrom(new FailStream());
+      fail("readFrom must throw the underlying IOException");
+
+    } catch (IOException e) {
+      assertEquals("readFrom must throw the expected exception",
+                   "synthetic failure", e.getMessage());
+    }
+  }
+
+  // Tests that ByteString.readFrom works with streams that don't
+  // always fill their buffers.
+  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));
+
+    // Same test as above, but with some specific chunk sizes.
+    assertReadFromReluctantStream(data, 100);
+    assertReadFromReluctantStream(data, 248);
+    assertReadFromReluctantStream(data, 249);
+    assertReadFromReluctantStream(data, 250);
+    assertReadFromReluctantStream(data, 251);
+    assertReadFromReluctantStream(data, 0x1000);
+    assertReadFromReluctantStream(data, 0x1001);
+  }
+
+  // Fails unless ByteString.readFrom reads the bytes correctly from a
+  // 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));
+  }
+
+  // Tests that ByteString.readFrom works with streams that implement
+  // available().
+  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));
+  }
+
+  // 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));
+  }
+
+  // A stream that fails when read.
+  private static final class FailStream extends InputStream {
+    @Override public int read() throws IOException {
+      throw new IOException("synthetic failure");
+    }
+  }
+
+  // A stream that simulates blocking by only producing 250 characters
+  // per call to read(byte[]).
+  private static class ReluctantStream extends InputStream {
+    protected final byte[] data;
+    protected int pos = 0;
+
+    public ReluctantStream(byte[] data) {
+      this.data = data;
+    }
+
+    @Override public int read() {
+      if (pos == data.length) {
+        return -1;
+      } else {
+        return data[pos++];
+      }
+    }
+
+    @Override public int read(byte[] buf) {
+      return read(buf, 0, buf.length);
+    }
+
+    @Override public int read(byte[] buf, int offset, int size) {
+      if (pos == data.length) {
+        return -1;
+      }
+      int count = Math.min(Math.min(size, data.length - pos), 250);
+      System.arraycopy(data, pos, buf, offset, count);
+      pos += count;
+      return count;
+    }
+  }
+
+  // Same as above, but also implements available().
+  private static final class AvailableStream extends ReluctantStream {
+    public AvailableStream(byte[] data) {
+      super(data);
+    }
+
+    @Override public int available() {
+      return Math.min(250, data.length - pos);
+    }
+  }
+
+  // A stream which exposes the byte array passed into read(byte[], int, int).
+  private static class EvilInputStream extends InputStream {
+    public byte[] capturedArray = null;
+
+    @Override
+    public int read(byte[] buf, int off, int len) {
+      if (capturedArray != null) {
+        return -1;
+      } else {
+        capturedArray = buf;
+        for (int x = 0; x < len; ++x) {
+          buf[x] = (byte) x;
+        }
+        return len;
+      }
+    }
+
+    @Override
+    public int read() {
+      // Purposefully do nothing.
+      return -1;
+    }
+  }
+  
+  // A stream which exposes the byte array passed into write(byte[], int, int).
+  private static class EvilOutputStream extends OutputStream {
+    public byte[] capturedArray = null;
+
+    @Override
+    public void write(byte[] buf, int off, int len) {
+      if (capturedArray == null) {
+        capturedArray = buf;
+      }
+    }
+
+    @Override
+    public void write(int ignored) {
+      // Purposefully do nothing.
+    }
+  }
+
+  public void testToStringUtf8() throws UnsupportedEncodingException {
+    String testString = "I love unicode \u1234\u5678 characters";
+    byte[] testBytes = testString.getBytes("UTF-8");
+    ByteString byteString = ByteString.copyFrom(testBytes);
+    assertEquals("copyToStringUtf8 must respect the charset",
+        testString, byteString.toStringUtf8());
+  }
+
+  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));
+  }
+
+  // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
+  // write sizes
+  public void testNewOutput_ArrayWrite() throws IOException {
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
+                         2 * length, 3 * length};
+    int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
+
+    for (int bufferSize : bufferSizes) {
+      for (int writeSize : writeSizes) {
+        // Test writing the entire output writeSize bytes at a time.
+        ByteString.Output output = ByteString.newOutput(bufferSize);
+        for (int i = 0; i < length; i += writeSize) {
+          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));
+      }
+    }
+  }
+
+  // Test newOutput() using a variety of buffer sizes, but writing all the
+  // characters using write(byte);
+  public void testNewOutput_WriteChar() throws IOException {
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {0, 1, 128, 256, length / 2,
+                         length - 1, length, length + 1,
+                         2 * length, 3 * length};
+    for (int bufferSize : bufferSizes) {
+      ByteString.Output output = ByteString.newOutput(bufferSize);
+      for (byte byteValue : bytes) {
+        output.write(byteValue);
+      }
+      ByteString byteString = output.toByteString();
+      assertTrue("String built from newOutput() must contain the expected bytes",
+          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    }
+  }
+
+  // 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.
+  public void testNewOutput_Mixed() throws IOException {
+    Random rng = new Random(1);
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {0, 1, 128, 256, length / 2,
+                         length - 1, length, length + 1,
+                         2 * length, 3 * length};
+
+    for (int bufferSize : bufferSizes) {
+      // Test writing the entire output using a mixture of write sizes and
+      // methods;
+      ByteString.Output output = ByteString.newOutput(bufferSize);
+      int position = 0;
+      while (position < bytes.length) {
+        if (rng.nextBoolean()) {
+          int count = 1 + rng.nextInt(bytes.length - position);
+          output.write(bytes, position, count);
+          position += count;
+        } else {
+          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));
+      }
+      ByteString byteString = output.toByteString();
+      assertTrue("String built from newOutput() must contain the expected bytes",
+          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    }
+  }
+  
+  public void testNewOutputEmpty() throws IOException {
+    // Make sure newOutput() correctly builds empty byte strings
+    ByteString byteString = ByteString.newOutput().toByteString();
+    assertEquals(ByteString.EMPTY, byteString);
+  }
+  
+  public void testNewOutput_Mutating() throws IOException {
+    Output os = ByteString.newOutput(5);
+    os.write(new byte[] {1, 2, 3, 4, 5});
+    EvilOutputStream eos = new EvilOutputStream();
+    os.writeTo(eos);
+    byte[] capturedArray = eos.capturedArray;
+    ByteString byteString = os.toByteString();
+    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));
+  }
+
+  public void testSubstringParity() {
+    byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
+    int start = 512 * 1024 - 3333;
+    int end   = 512 * 1024 + 7777;
+    ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
+    boolean ok = true;
+    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);
+
+    ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
+    assertTrue("Substring must be equal to literal string",
+        concreteSubstring.equals(literalString));
+    assertEquals("Substring must have same hashcode as literal string",
+        literalString.hashCode(), concreteSubstring.hashCode());
+  }
+
+  public void testCompositeSubstring() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+    ByteString listString = ByteString.copyFrom(pieces);
+
+    int from = 1000;
+    int to = 40000;
+    ByteString compositeSubstring = listString.substring(from, to);
+    byte[] substringBytes = compositeSubstring.toByteArray();
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < to - from; ++i) {
+      stillEqual = referenceBytes[from + i] == substringBytes[i];
+    }
+    assertTrue("Substring must return correct bytes", stillEqual);
+
+    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);
+
+    ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
+    assertTrue("Composite substring must equal a literal substring over the same bytes",
+        compositeSubstring.equals(literalSubstring));
+    assertTrue("Literal substring must equal a composite substring over the same bytes",
+        literalSubstring.equals(compositeSubstring));
+
+    assertEquals("We must get the same hashcodes for composite and literal substrings",
+        literalSubstring.hashCode(), compositeSubstring.hashCode());
+
+    assertFalse("We can't be equal to a proper substring",
+        compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
+  }
+
+  public void testCopyFromList() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+    ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+    ByteString listString = ByteString.copyFrom(pieces);
+
+    assertTrue("Composite string must be equal to literal string",
+        listString.equals(literalString));
+    assertEquals("Composite string must have same hashcode as literal string",
+        literalString.hashCode(), listString.hashCode());
+  }
+
+  public void testConcat() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+    ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+
+    Iterator<ByteString> iter = pieces.iterator();
+    ByteString concatenatedString = iter.next();
+    while (iter.hasNext()) {
+      concatenatedString = concatenatedString.concat(iter.next());
+    }
+
+    assertTrue("Concatenated string must be equal to literal string",
+        concatenatedString.equals(literalString));
+    assertEquals("Concatenated string must have same hashcode as literal string",
+        literalString.hashCode(), concatenatedString.hashCode());
+  }
+
+  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));
+  }
+
+  static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
+    List<ByteString> pieces = new ArrayList<ByteString>();
+    // Starting length should be small enough that we'll do some concatenating by
+    // copying if we just concatenate all these pieces together.
+    for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
+      length = (length << 1) - 1;
+      if (start + length > referenceBytes.length) {
+        length = referenceBytes.length - start;
+      }
+      pieces.add(ByteString.copyFrom(referenceBytes, start, length));
+    }
+    return pieces;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedInputStreamTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedInputStreamTest.java
new file mode 100644
index 0000000..7e67898
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedInputStreamTest.java
@@ -0,0 +1,469 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRecursiveMessage;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Unit test for {@link CodedInputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedInputStreamTest extends TestCase {
+  /**
+   * Helper to construct a byte array from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private byte[] bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return bytes;
+  }
+
+  /**
+   * An InputStream which limits the number of bytes it reads at a time.
+   * We use this to make sure that CodedInputStream doesn't screw up when
+   * reading in small blocks.
+   */
+  private static final class SmallBlockInputStream extends FilterInputStream {
+    private final int blockSize;
+
+    public SmallBlockInputStream(byte[] data, int blockSize) {
+      this(new ByteArrayInputStream(data), blockSize);
+    }
+
+    public SmallBlockInputStream(InputStream in, int blockSize) {
+      super(in);
+      this.blockSize = blockSize;
+    }
+
+    public int read(byte[] b) throws IOException {
+      return super.read(b, 0, Math.min(b.length, blockSize));
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+      return super.read(b, off, Math.min(len, blockSize));
+    }
+  }
+
+  /**
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+   * checks that the result matches the given value.
+   */
+  private void assertReadVarint(byte[] data, long value) throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals((int)value, input.readRawVarint32());
+
+    input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawVarint64());
+    assertTrue(input.isAtEnd());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals((int)value, input.readRawVarint32());
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawVarint64());
+      assertTrue(input.isAtEnd());
+    }
+
+    // Try reading direct from an InputStream.  We want to verify that it
+    // doesn't read past the end of the input, so we copy to a new, bigger
+    // array first.
+    byte[] longerData = new byte[data.length + 1];
+    System.arraycopy(data, 0, longerData, 0, data.length);
+    InputStream rawInput = new ByteArrayInputStream(longerData);
+  }
+
+  /**
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+   * expects them to fail with an InvalidProtocolBufferException whose
+   * description matches the given one.
+   */
+  private void assertReadVarintFailure(
+      InvalidProtocolBufferException expected, byte[] data)
+      throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint32();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+
+    input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint64();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+  }
+
+  /** Tests readRawVarint32() and readRawVarint64(). */
+  public void testReadVarint() throws Exception {
+    assertReadVarint(bytes(0x00), 0);
+    assertReadVarint(bytes(0x01), 1);
+    assertReadVarint(bytes(0x7f), 127);
+    // 14882
+    assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+    // 2961488830
+    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x0bL << 28));
+
+    // 64-bit
+    // 7256456126
+    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x1bL << 28));
+    // 41256202580718336
+    assertReadVarint(
+      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+    // 11964378330978735131
+    assertReadVarint(
+      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+  }
+
+  /**
+   * Parses the given bytes using readRawLittleEndian32() and checks
+   * that the result matches the given value.
+   */
+  private void assertReadLittleEndian32(byte[] data, int value)
+                                        throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawLittleEndian32());
+    assertTrue(input.isAtEnd());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawLittleEndian32());
+      assertTrue(input.isAtEnd());
+    }
+  }
+
+  /**
+   * Parses the given bytes using readRawLittleEndian64() and checks
+   * that the result matches the given value.
+   */
+  private void assertReadLittleEndian64(byte[] data, long value)
+                                        throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawLittleEndian64());
+    assertTrue(input.isAtEnd());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawLittleEndian64());
+      assertTrue(input.isAtEnd());
+    }
+  }
+
+  /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
+  public void testReadLittleEndian() throws Exception {
+    assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+    assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+    assertReadLittleEndian64(
+      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+      0x123456789abcdef0L);
+    assertReadLittleEndian64(
+      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+      0x9abcdef012345678L);
+  }
+
+  /** Test decodeZigZag32() and decodeZigZag64(). */
+  public void testDecodeZigZag() throws Exception {
+    assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+    assertEquals(-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));
+
+    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));
+  }
+
+  /** Tests reading and parsing a whole message with every field type. */
+  public void testReadWholeMessage() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    byte[] rawBytes = message.toByteArray();
+    assertEquals(rawBytes.length, message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+    TestUtil.assertAllFieldsSet(message2);
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+      message2 = TestAllTypes.parseFrom(
+        new SmallBlockInputStream(rawBytes, blockSize));
+      TestUtil.assertAllFieldsSet(message2);
+    }
+  }
+
+  /** Tests skipField(). */
+  public void testSkipWholeMessage() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+    byte[] rawBytes = message.toByteArray();
+
+    // Create two parallel inputs.  Parse one as unknown fields while using
+    // skipField() to skip each field on the other.  Expect the same tags.
+    CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
+    CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+    UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
+
+    while (true) {
+      int tag = input1.readTag();
+      assertEquals(tag, input2.readTag());
+      if (tag == 0) {
+        break;
+      }
+      unknownFields.mergeFieldFrom(tag, input1);
+      input2.skipField(tag);
+    }
+  }
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * exactly up to a limit, this should not break things.
+   */
+  public void testSkipRawBytesBug() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2 };
+    CodedInputStream input = CodedInputStream.newInstance(rawBytes);
+
+    int limit = input.pushLimit(1);
+    input.skipRawBytes(1);
+    input.popLimit(limit);
+    assertEquals(2, input.readRawByte());
+  }
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * past the end of a buffer with a limit that has been set past the end of
+   * that buffer, this should not break things.
+   */
+  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(rawBytes, 3));
+
+    int limit = input.pushLimit(4);
+    // In order to expose the bug we need to read at least one byte to prime the
+    // buffer inside the CodedInputStream.
+    assertEquals(1, input.readRawByte());
+    // Skip to the end of the limit.
+    input.skipRawBytes(3);
+    assertTrue(input.isAtEnd());
+    input.popLimit(limit);
+    assertEquals(5, input.readRawByte());
+  }
+
+  public void testReadHugeBlob() throws Exception {
+    // Allocate and initialize a 1MB blob.
+    byte[] blob = new byte[1 << 20];
+    for (int i = 0; i < blob.length; i++) {
+      blob[i] = (byte)i;
+    }
+
+    // Make a message containing it.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    builder.setOptionalBytes(ByteString.copyFrom(blob));
+    TestAllTypes message = builder.build();
+
+    // Serialize and parse it.  Make sure to parse from an InputStream, not
+    // directly from a ByteString, so that CodedInputStream uses buffered
+    // reading.
+    TestAllTypes message2 =
+      TestAllTypes.parseFrom(message.toByteString().newInput());
+
+    assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
+
+    // Make sure all the other fields were parsed correctly.
+    TestAllTypes message3 = TestAllTypes.newBuilder(message2)
+      .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+      .build();
+    TestUtil.assertAllFieldsSet(message3);
+  }
+
+  public int makeTag(int number, int tag) {
+    return (number << 3) + tag;
+  }
+
+  public void testReadMaliciouslyLargeBlob() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(0x7FFFFFFF);
+    output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+
+    try {
+      input.readBytes();
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException e) {
+      // success.
+    }
+  }
+
+  private TestRecursiveMessage makeRecursiveMessage(int depth) {
+    if (depth == 0) {
+      return TestRecursiveMessage.newBuilder().setI(5).build();
+    } else {
+      return TestRecursiveMessage.newBuilder()
+        .setA(makeRecursiveMessage(depth - 1)).build();
+    }
+  }
+
+  private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+    if (depth == 0) {
+      assertFalse(message.hasA());
+      assertEquals(5, message.getI());
+    } else {
+      assertTrue(message.hasA());
+      assertMessageDepth(message.getA(), depth - 1);
+    }
+  }
+
+  public void testResetSizeCounter() throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(new byte[256], 8));
+    input.setSizeLimit(16);
+    input.readRawBytes(16);
+    assertEquals(16, input.getTotalBytesRead());
+
+    try {
+      input.readRawByte();
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException e) {
+      // success.
+    }
+
+    input.resetSizeCounter();
+    assertEquals(0, input.getTotalBytesRead());
+    input.readRawByte();  // No exception thrown.
+    input.resetSizeCounter();
+    assertEquals(0, input.getTotalBytesRead());
+  }
+
+  /**
+   * Tests that if we read an string that contains invalid UTF-8, no exception
+   * is thrown.  Instead, the invalid bytes are replaced with the Unicode
+   * "replacement character" U+FFFD.
+   */
+  public void testReadInvalidUtf8() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte)0x80 });
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+    String text = input.readString();
+    assertEquals(0xfffd, text.charAt(0));
+  }
+
+  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());
+    for (int i = 3; i < 8; i++) {
+      assertEquals(i, in.readRawByte());
+      assertEquals(i-2, in.getTotalBytesRead());
+    }
+    // eof
+    assertEquals(0, in.readTag());
+    assertEquals(5, in.getTotalBytesRead());
+  }
+
+  public void testInvalidTag() throws Exception {
+    // Any tag number which corresponds to field number zero is invalid and
+    // should throw InvalidProtocolBufferException.
+    for (int i = 0; i < 8; i++) {
+      try {
+        CodedInputStream.newInstance(bytes(i)).readTag();
+        fail("Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+      }
+    }
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedOutputStreamTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedOutputStreamTest.java
new file mode 100644
index 0000000..354d89d
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/CodedOutputStreamTest.java
@@ -0,0 +1,318 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto.SparseEnumMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestSparseEnum;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test for {@link CodedOutputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedOutputStreamTest extends TestCase {
+  /**
+   * Helper to construct a byte array from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private byte[] bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return bytes;
+  }
+
+  /** Arrays.asList() does not work with arrays of primitives.  :( */
+  private List<Byte> toList(byte[] bytes) {
+    List<Byte> result = new ArrayList<Byte>();
+    for (byte b : bytes) {
+      result.add(b);
+    }
+    return result;
+  }
+
+  private void assertEqualBytes(byte[] a, byte[] b) {
+    assertEquals(toList(a), toList(b));
+  }
+
+  /**
+   * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+   * checks that the result matches the given bytes.
+   */
+  private void assertWriteVarint(byte[] data, long value) throws Exception {
+    // Only do 32-bit write if the value fits in 32 bits.
+    if ((value >>> 32) == 0) {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint32((int) value);
+      output.flush();
+      assertEqualBytes(data, rawOutput.toByteArray());
+
+      // Also try computing size.
+      assertEquals(data.length,
+                   CodedOutputStream.computeRawVarint32Size((int) value));
+    }
+
+    {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint64(value);
+      output.flush();
+      assertEqualBytes(data, rawOutput.toByteArray());
+
+      // Also try computing size.
+      assertEquals(data.length,
+                   CodedOutputStream.computeRawVarint64Size(value));
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      // Only do 32-bit write if the value fits in 32 bits.
+      if ((value >>> 32) == 0) {
+        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+        CodedOutputStream output =
+          CodedOutputStream.newInstance(rawOutput, blockSize);
+        output.writeRawVarint32((int) value);
+        output.flush();
+        assertEqualBytes(data, rawOutput.toByteArray());
+      }
+
+      {
+        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+        CodedOutputStream output =
+          CodedOutputStream.newInstance(rawOutput, blockSize);
+        output.writeRawVarint64(value);
+        output.flush();
+        assertEqualBytes(data, rawOutput.toByteArray());
+      }
+    }
+  }
+
+  /** Tests writeRawVarint32() and writeRawVarint64(). */
+  public void testWriteVarint() throws Exception {
+    assertWriteVarint(bytes(0x00), 0);
+    assertWriteVarint(bytes(0x01), 1);
+    assertWriteVarint(bytes(0x7f), 127);
+    // 14882
+    assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+    // 2961488830
+    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x0bL << 28));
+
+    // 64-bit
+    // 7256456126
+    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x1bL << 28));
+    // 41256202580718336
+    assertWriteVarint(
+      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+    // 11964378330978735131
+    assertWriteVarint(
+      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+  }
+
+  /**
+   * Parses the given bytes using writeRawLittleEndian32() and checks
+   * that the result matches the given value.
+   */
+  private void assertWriteLittleEndian32(byte[] data, int value)
+                                         throws Exception {
+    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    output.writeRawLittleEndian32(value);
+    output.flush();
+    assertEqualBytes(data, rawOutput.toByteArray());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      rawOutput = new ByteArrayOutputStream();
+      output = CodedOutputStream.newInstance(rawOutput, blockSize);
+      output.writeRawLittleEndian32(value);
+      output.flush();
+      assertEqualBytes(data, rawOutput.toByteArray());
+    }
+  }
+
+  /**
+   * Parses the given bytes using writeRawLittleEndian64() and checks
+   * that the result matches the given value.
+   */
+  private void assertWriteLittleEndian64(byte[] data, long value)
+                                         throws Exception {
+    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    output.writeRawLittleEndian64(value);
+    output.flush();
+    assertEqualBytes(data, rawOutput.toByteArray());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      rawOutput = new ByteArrayOutputStream();
+      output = CodedOutputStream.newInstance(rawOutput, blockSize);
+      output.writeRawLittleEndian64(value);
+      output.flush();
+      assertEqualBytes(data, rawOutput.toByteArray());
+    }
+  }
+
+  /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
+  public void testWriteLittleEndian() throws Exception {
+    assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+    assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+    assertWriteLittleEndian64(
+      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+      0x123456789abcdef0L);
+    assertWriteLittleEndian64(
+      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+      0x9abcdef012345678L);
+  }
+
+  /** Test encodeZigZag32() and encodeZigZag64(). */
+  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));
+
+    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));
+
+    // 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)));
+
+    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)));
+
+    assertEquals(856912304801416L,
+      CodedOutputStream.encodeZigZag64(
+        CodedInputStream.decodeZigZag64(
+          856912304801416L)));
+    assertEquals(-75123905439571256L,
+      CodedOutputStream.encodeZigZag64(
+        CodedInputStream.decodeZigZag64(
+          -75123905439571256L)));
+  }
+
+  /** Tests writing a whole message with every field type. */
+  public void testWriteWholeMessage() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    byte[] rawBytes = message.toByteArray();
+    assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output =
+        CodedOutputStream.newInstance(rawOutput, blockSize);
+      message.writeTo(output);
+      output.flush();
+      assertEqualBytes(rawBytes, rawOutput.toByteArray());
+    }
+  }
+
+  /** Tests writing a whole message with every packed field type. Ensures the
+   * wire format of packed fields is compatible with C++. */
+  public void testWriteWholePackedFieldsMessage() throws Exception {
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    byte[] rawBytes = message.toByteArray();
+    assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
+                     rawBytes);
+  }
+
+  /** 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.
+   */
+  public void testWriteMessageWithNegativeEnumValue() throws Exception {
+    SparseEnumMessage message = SparseEnumMessage.newBuilder()
+        .setSparseEnum(TestSparseEnum.SPARSE_E) .build();
+    assertTrue(message.getSparseEnum().getNumber() < 0);
+    byte[] rawBytes = message.toByteArray();
+    SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
+    assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DeprecatedFieldTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DeprecatedFieldTest.java
new file mode 100644
index 0000000..ee4e767
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DeprecatedFieldTest.java
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto.TestDeprecatedFields;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+/**
+ * Test field deprecation
+ * 
+ * @author birdo@google.com (Roberto Scaramuzzi)
+ */
+public class DeprecatedFieldTest extends TestCase {
+  private String[] deprecatedGetterNames = {
+      "hasDeprecatedInt32",
+      "getDeprecatedInt32"};
+  
+  private String[] deprecatedBuilderGetterNames = {
+      "hasDeprecatedInt32",
+      "getDeprecatedInt32",
+      "clearDeprecatedInt32"};
+  
+  private String[] deprecatedBuilderSetterNames = {
+      "setDeprecatedInt32"}; 
+  
+  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));
+    }
+    for (String name : deprecatedBuilderGetterNames) {
+      Method method = deprecatedFieldsBuilder.getMethod(name);
+      assertTrue("Method " + name + " should be deprecated",
+          isDeprecated(method));
+    }
+    for (String name : deprecatedBuilderSetterNames) {
+      Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
+      assertTrue("Method " + name + " should be deprecated",
+          isDeprecated(method));
+    }
+  }
+  
+  private boolean isDeprecated(AnnotatedElement annotated) {
+    return annotated.isAnnotationPresent(Deprecated.class);
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DescriptorsTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DescriptorsTest.java
new file mode 100644
index 0000000..aabd7b4
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DescriptorsTest.java
@@ -0,0 +1,649 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
+import com.google.protobuf.Descriptors.DescriptorValidationException;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.ServiceDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+
+import com.google.protobuf.test.UnittestImport;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestService;
+import protobuf_unittest.UnittestCustomOptions;
+
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unit test for {@link Descriptors}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DescriptorsTest extends TestCase {
+
+  // Regression test for bug where referencing a FieldDescriptor.Type value
+  // before a FieldDescriptorProto.Type value would yield a
+  // ExceptionInInitializerError.
+  @SuppressWarnings("unused")
+  private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
+
+  public void testFieldTypeEnumMapping() throws Exception {
+    assertEquals(FieldDescriptor.Type.values().length,
+        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));
+    }
+  }
+
+  public void testFileDescriptor() throws Exception {
+    FileDescriptor file = UnittestProto.getDescriptor();
+
+    assertEquals("google/protobuf/unittest.proto", file.getName());
+    assertEquals("protobuf_unittest", file.getPackage());
+
+    assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
+    assertEquals("google/protobuf/unittest.proto",
+                 file.toProto().getName());
+
+    assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
+                 file.getDependencies());
+
+    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"));
+    for (int i = 0; i < file.getMessageTypes().size(); i++) {
+      assertEquals(i, file.getMessageTypes().get(i).getIndex());
+    }
+
+    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()),
+                 UnittestImport.getDescriptor().getEnumTypes());
+    for (int i = 0; i < file.getEnumTypes().size(); i++) {
+      assertEquals(i, file.getEnumTypes().get(i).getIndex());
+    }
+
+    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());
+    for (int i = 0; i < file.getServices().size(); i++) {
+      assertEquals(i, file.getServices().get(i).getIndex());
+    }
+
+    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());
+    for (int i = 0; i < file.getExtensions().size(); i++) {
+      assertEquals(i, file.getExtensions().get(i).getIndex());
+    }
+  }
+
+  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());
+
+    assertEquals("NestedMessage", nestedType.getName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
+                 nestedType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+    assertEquals(messageType, nestedType.getContainingType());
+
+    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));
+    for (int i = 0; i < messageType.getFields().size(); i++) {
+      assertEquals(i, messageType.getFields().get(i).getIndex());
+    }
+
+    assertEquals(nestedType, messageType.getNestedTypes().get(0));
+    assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
+    assertNull(messageType.findNestedTypeByName("NoSuchType"));
+    for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
+      assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
+    }
+
+    EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+    assertEquals(enumType, messageType.getEnumTypes().get(0));
+    assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
+    assertNull(messageType.findEnumTypeByName("NoSuchType"));
+    for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
+      assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
+    }
+  }
+
+  public void testFieldDescriptor() throws Exception {
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    FieldDescriptor primitiveField =
+      messageType.findFieldByName("optional_int32");
+    FieldDescriptor enumField =
+      messageType.findFieldByName("optional_nested_enum");
+    FieldDescriptor messageField =
+      messageType.findFieldByName("optional_foreign_message");
+    FieldDescriptor cordField =
+      messageType.findFieldByName("optional_cord");
+    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());
+
+    assertEquals("optional_nested_enum", enumField.getName());
+    assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
+    assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
+    assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
+                 enumField.getEnumType());
+
+    assertEquals("optional_foreign_message", messageField.getName());
+    assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
+    assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
+    assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
+
+    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());
+
+    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());
+
+    assertEquals("single", nestedExtension.getName());
+    assertEquals("protobuf_unittest.TestRequired.single",
+                 nestedExtension.getFullName());
+    assertEquals(TestRequired.getDescriptor(),
+                 nestedExtension.getExtensionScope());
+  }
+
+  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());
+  }
+
+  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());
+
+    d = TestExtremeDefaultValues.getDescriptor();
+    assertEquals(
+      ByteString.copyFrom(
+        "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
+      d.findFieldByName("escaped_bytes").getDefaultValue());
+    assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
+    assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
+  }
+
+  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());
+
+    assertEquals("NestedEnum", nestedType.getName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
+                 nestedType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+    assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
+
+    EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
+    assertEquals(value, enumType.getValues().get(0));
+    assertEquals("FOREIGN_FOO", value.getName());
+    assertEquals(4, value.getNumber());
+    assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
+    assertEquals(value, enumType.findValueByNumber(4));
+    assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
+    for (int i = 0; i < enumType.getValues().size(); i++) {
+      assertEquals(i, enumType.getValues().get(i).getIndex());
+    }
+  }
+
+  public void testServiceDescriptor() throws Exception {
+    ServiceDescriptor service = TestService.getDescriptor();
+
+    assertEquals("TestService", service.getName());
+    assertEquals("protobuf_unittest.TestService", service.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), service.getFile());
+
+    assertEquals(2, service.getMethods().size());
+
+    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"));
+
+    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"));
+
+    assertNull(service.findMethodByName("NoSuchMethod"));
+
+    for (int i = 0; i < service.getMethods().size(); i++) {
+      assertEquals(i, service.getMethods().get(i).getIndex());
+    }
+  }
+
+
+  public void testCustomOptions() throws Exception {
+    Descriptor descriptor =
+      UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
+
+    assertTrue(
+      descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
+    assertEquals(Integer.valueOf(-56),
+      descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+
+    FieldDescriptor field = descriptor.findFieldByName("field1");
+    assertNotNull(field);
+
+    assertTrue(
+      field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
+    assertEquals(Long.valueOf(8765432109L),
+      field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+
+    EnumDescriptor enumType =
+      UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
+
+    assertTrue(
+      enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
+    assertEquals(Integer.valueOf(-789),
+      enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+
+    ServiceDescriptor service =
+      UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
+
+    assertTrue(
+      service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
+    assertEquals(Long.valueOf(-9876543210L),
+      service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+
+    MethodDescriptor method = service.findMethodByName("Foo");
+    assertNotNull(method);
+
+    assertTrue(
+      method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
+    assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
+      method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+  }
+
+  /**
+   * Test that the FieldDescriptor.Type enum is the same as the
+   * WireFormat.FieldType enum.
+   */
+  public void testFieldTypeTablesMatch() throws Exception {
+    FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
+    WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
+
+  /**
+   * Test that the FieldDescriptor.JavaType enum is the same as the
+   * WireFormat.JavaType enum.
+   */
+  public void testJavaTypeTablesMatch() throws Exception {
+    FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
+    WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
+
+  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);
+  }
+
+  /**
+   * Tests that the DescriptorValidationException works as intended.
+   */
+  public void testDescriptorValidatorException() throws Exception {
+    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+      .setName("foo.proto")
+      .addMessageType(DescriptorProto.newBuilder()
+      .setName("Foo")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setType(FieldDescriptorProto.Type.TYPE_INT32)
+          .setName("foo")
+          .setNumber(1)
+          .setDefaultValue("invalid")
+          .build())
+        .build())
+      .build();
+    try {
+      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
+          new FileDescriptor[0]);
+      fail("DescriptorValidationException expected");
+    } 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);
+    }
+  }
+
+  /**
+   * Tests the translate/crosslink for an example where a message field's name
+   * and type name are the same.
+   */
+  public void testDescriptorComplexCrosslink() throws Exception {
+    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+      .setName("foo.proto")
+      .addMessageType(DescriptorProto.newBuilder()
+        .setName("Foo")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setType(FieldDescriptorProto.Type.TYPE_INT32)
+          .setName("foo")
+          .setNumber(1)
+          .build())
+        .build())
+      .addMessageType(DescriptorProto.newBuilder()
+        .setName("Bar")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setTypeName("Foo")
+          .setName("Foo")
+          .setNumber(1)
+          .build())
+        .build())
+      .build();
+    // translate and crosslink
+    FileDescriptor file =
+      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, 
+          new FileDescriptor[0]);
+    // verify resulting descriptors
+    assertNotNull(file);
+    List<Descriptor> msglist = file.getMessageTypes();
+    assertNotNull(msglist);
+    assertTrue(msglist.size() == 2);
+    boolean barFound = false;
+    for (Descriptor desc : msglist) {
+      if (desc.getName().equals("Bar")) {
+        barFound = true;
+        assertNotNull(desc.getFields());
+        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"));
+      }
+    }
+    assertTrue(barFound);
+  }
+  
+  public void testInvalidPublicDependency() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto") .build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("boo.proto")
+        .addDependency("foo.proto")
+        .addPublicDependency(1)  // Error, should be 0.
+        .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+        new FileDescriptor[0]);
+    try {
+      Descriptors.FileDescriptor.buildFrom(barProto,
+          new FileDescriptor[] {fooFile});
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(
+          e.getMessage().indexOf("Invalid public dependency index.") != -1);
+    }
+  }
+
+  public void testHiddenDependency() throws Exception {
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+        .build();
+    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+        .setName("forward.proto")
+        .addDependency("bar.proto")
+        .build();
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("forward.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+        forwardProto, new FileDescriptor[] {barFile});
+
+    try {
+      Descriptors.FileDescriptor.buildFrom(
+          fooProto, new FileDescriptor[] {forwardFile});
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(e.getMessage().indexOf("Bar") != -1);
+      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+    }
+  }
+
+  public void testPublicDependency() throws Exception {
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+        .build();
+    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+        .setName("forward.proto")
+        .addDependency("bar.proto")
+        .addPublicDependency(0)
+        .build();
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("forward.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+        forwardProto, new FileDescriptor[]{barFile});
+    Descriptors.FileDescriptor.buildFrom(
+        fooProto, new FileDescriptor[] {forwardFile});
+  }
+  
+  /**
+   * Tests the translate/crosslink for an example with a more complex namespace
+   * referencing.
+   */
+  public void testComplexNamespacePublicDependency() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .setPackage("a.b.c.d.bar.shared")
+        .addEnumType(EnumDescriptorProto.newBuilder()
+            .setName("MyEnum")
+            .addValue(EnumValueDescriptorProto.newBuilder()
+                .setName("BLAH")
+                .setNumber(1)))
+        .build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("bar.proto")
+        .setPackage("a.b.c.d.foo.shared")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("MyMessage")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+                .setTypeName("bar.shared.MyEnum")
+                .setName("MyField")
+                .setNumber(1)))
+        .build();
+    // translate and crosslink
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
+        fooProto, new FileDescriptor[0]);
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[]{fooFile});
+    // verify resulting descriptors
+    assertNotNull(barFile);
+    List<Descriptor> msglist = barFile.getMessageTypes();
+    assertNotNull(msglist);
+    assertTrue(msglist.size() == 1);
+    Descriptor desc = msglist.get(0);
+    if (desc.getName().equals("MyMessage")) {
+      assertNotNull(desc.getFields());
+      List<FieldDescriptor> fieldlist = desc.getFields();
+      assertNotNull(fieldlist);
+      assertTrue(fieldlist.size() == 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"));
+    }   
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DynamicMessageTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DynamicMessageTest.java
new file mode 100644
index 0000000..0023067
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/DynamicMessageTest.java
@@ -0,0 +1,265 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+
+import junit.framework.TestCase;
+import java.util.Arrays;
+
+/**
+ * Unit test for {@link DynamicMessage}.  See also {@link MessageTest}, which
+ * tests some {@link DynamicMessage} functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DynamicMessageTest extends TestCase {
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+  TestUtil.ReflectionTester packedReflectionTester =
+    new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
+
+  public void testDynamicMessageAccessors() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testSettersAfterBuild() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    Message firstMessage = builder.build();
+    // double build()
+    builder.build();
+    // clear() after build()
+    builder.clear();
+    // setters after build()
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+    // repeated setters after build()
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    message = builder.build();
+    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+    // firstMessage shouldn't have been modified.
+    reflectionTester.assertClearViaReflection(firstMessage);
+  }
+
+  public void testUnknownFields() throws Exception {
+    Message.Builder builder =
+        DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
+    builder.setUnknownFields(UnknownFieldSet.newBuilder()
+        .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
+        .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
+        .build());
+    Message message = builder.build();
+    assertEquals(2, message.getUnknownFields().asMap().size());
+    // clone() with unknown fields
+    Message.Builder newBuilder = builder.clone();
+    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+    // clear() with unknown fields
+    newBuilder.clear();
+    assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
+    // serialize/parse with unknown fields
+    newBuilder.mergeFrom(message.toByteString());
+    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+  }
+
+  public void testDynamicMessageSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  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.
+    // It treats them just like any other fields.
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testDynamicMessageRepeatedSetters() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+  }
+
+  public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+  }
+
+  public void testDynamicMessageDefaults() throws Exception {
+    reflectionTester.assertClearViaReflection(
+      DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
+    reflectionTester.assertClearViaReflection(
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
+  }
+
+  public void testDynamicMessageSerializedSize() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    Message.Builder dynamicBuilder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
+    Message dynamicMessage = dynamicBuilder.build();
+
+    assertEquals(message.getSerializedSize(),
+                 dynamicMessage.getSerializedSize());
+  }
+
+  public void testDynamicMessageSerialization() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+
+    // In fact, the serialized forms should be exactly the same, byte-for-byte.
+    assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
+  }
+
+  public void testDynamicMessageParsing() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+
+    Message message2 =
+      DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
+    reflectionTester.assertAllFieldsSetViaReflection(message2);
+
+    // Test Parser interface.
+    Message message3 = message2.getParserForType().parseFrom(rawBytes);
+    reflectionTester.assertAllFieldsSetViaReflection(message3);
+  }
+
+  public void testDynamicMessageExtensionParsing() throws Exception {
+    ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
+    Message message = DynamicMessage.parseFrom(
+        TestAllExtensions.getDescriptor(), rawBytes,
+        TestUtil.getExtensionRegistry());
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+
+    // Test Parser interface.
+    Message message2 = message.getParserForType().parseFrom(
+        rawBytes, TestUtil.getExtensionRegistry());
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
+  }
+
+  public void testDynamicMessagePackedSerialization() throws Exception {
+    Message.Builder builder =
+        DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
+    packedReflectionTester.setPackedFieldsViaReflection(builder);
+    Message message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+    TestUtil.assertPackedFieldsSet(message2);
+
+    // In fact, the serialized forms should be exactly the same, byte-for-byte.
+    assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
+  }
+
+  public void testDynamicMessagePackedParsing() throws Exception {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    TestUtil.setPackedFields(builder);
+    TestPackedTypes message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+
+    Message message2 =
+      DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
+    packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
+
+    // Test Parser interface.
+    Message message3 = message2.getParserForType().parseFrom(rawBytes);
+    packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
+  }
+
+  public void testDynamicMessageCopy() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    DynamicMessage copy = DynamicMessage.newBuilder(message).build();
+    reflectionTester.assertAllFieldsSetViaReflection(copy);
+  }
+
+  public void testToBuilder() throws Exception {
+    DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    int unknownFieldNum = 9;
+    long unknownFieldVal = 90;
+    builder.setUnknownFields(UnknownFieldSet.newBuilder()
+        .addField(unknownFieldNum,
+            UnknownFieldSet.Field.newBuilder()
+                .addVarint(unknownFieldVal).build())
+        .build());
+    DynamicMessage message = builder.build();
+
+    DynamicMessage derived = message.toBuilder().build();
+    reflectionTester.assertAllFieldsSetViaReflection(derived);
+    assertEquals(Arrays.asList(unknownFieldVal),
+        derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ForceFieldBuildersPreRun.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ForceFieldBuildersPreRun.java
new file mode 100644
index 0000000..6a39500
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ForceFieldBuildersPreRun.java
@@ -0,0 +1,49 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+/**
+ * A prerun for a test suite that allows running the full protocol buffer
+ * tests in a mode that disables the optimization for not using
+ * {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are
+ * requested. This allows us to run all the tests through both code paths
+ * and ensures that both code paths produce identical results.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class ForceFieldBuildersPreRun implements Runnable {
+
+  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  public void run() {
+    // GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/GeneratedMessageTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/GeneratedMessageTest.java
new file mode 100644
index 0000000..49f1146
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/GeneratedMessageTest.java
@@ -0,0 +1,961 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.test.UnittestImport;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.MultipleFilesTestProto;
+import protobuf_unittest.NestedExtension.MyNestedExtension;
+import protobuf_unittest.NonNestedExtension;
+import protobuf_unittest.NonNestedExtension.MessageToBeExtended;
+import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
+import protobuf_unittest.ServiceWithNoOuter;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unit test for generated messages and generated code.  See also
+ * {@link MessageTest}, which tests some generated message functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class GeneratedMessageTest extends TestCase {
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  public void testDefaultInstance() throws Exception {
+    assertSame(TestAllTypes.getDefaultInstance(),
+               TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
+    assertSame(TestAllTypes.getDefaultInstance(),
+               TestAllTypes.newBuilder().getDefaultInstanceForType());
+  }
+
+  public void testMessageOrBuilder() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+  }
+
+  public void testUsingBuilderMultipleTimes() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    // primitive field scalar and repeated
+    builder.setOptionalSfixed64(100);
+    builder.addRepeatedInt32(100);
+    // enum field scalar and repeated
+    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    // proto field scalar and repeated
+    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(1));
+    builder.addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(1));
+
+    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());
+
+    // Make sure that builder didn't update previously created values
+    builder.setOptionalSfixed64(200);
+    builder.setRepeatedInt32(0, 200);
+    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_FOO);
+    builder.setRepeatedImportEnum(0, UnittestImport.ImportEnum.IMPORT_FOO);
+    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(2));
+    builder.setRepeatedForeignMessage(0, ForeignMessage.newBuilder().setC(2));
+
+    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());
+
+    // 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());
+  }
+
+  public void testRepeatedArraysAreImmutable() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addRepeatedInt32(100);
+    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance());
+    assertIsUnmodifiable(builder.getRepeatedInt32List());
+    assertIsUnmodifiable(builder.getRepeatedImportEnumList());
+    assertIsUnmodifiable(builder.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(builder.getRepeatedFloatList());
+
+
+    TestAllTypes value = builder.build();
+    assertIsUnmodifiable(value.getRepeatedInt32List());
+    assertIsUnmodifiable(value.getRepeatedImportEnumList());
+    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(value.getRepeatedFloatList());
+  }
+
+  public void testParsedMessagesAreImmutable() throws Exception {
+    TestAllTypes value = TestAllTypes.PARSER.parseFrom(
+        TestUtil.getAllSet().toByteString());
+    assertIsUnmodifiable(value.getRepeatedInt32List());
+    assertIsUnmodifiable(value.getRepeatedInt64List());
+    assertIsUnmodifiable(value.getRepeatedUint32List());
+    assertIsUnmodifiable(value.getRepeatedUint64List());
+    assertIsUnmodifiable(value.getRepeatedSint32List());
+    assertIsUnmodifiable(value.getRepeatedSint64List());
+    assertIsUnmodifiable(value.getRepeatedFixed32List());
+    assertIsUnmodifiable(value.getRepeatedFixed64List());
+    assertIsUnmodifiable(value.getRepeatedSfixed32List());
+    assertIsUnmodifiable(value.getRepeatedSfixed64List());
+    assertIsUnmodifiable(value.getRepeatedFloatList());
+    assertIsUnmodifiable(value.getRepeatedDoubleList());
+    assertIsUnmodifiable(value.getRepeatedBoolList());
+    assertIsUnmodifiable(value.getRepeatedStringList());
+    assertIsUnmodifiable(value.getRepeatedBytesList());
+    assertIsUnmodifiable(value.getRepeatedGroupList());
+    assertIsUnmodifiable(value.getRepeatedNestedMessageList());
+    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(value.getRepeatedImportMessageList());
+    assertIsUnmodifiable(value.getRepeatedNestedEnumList());
+    assertIsUnmodifiable(value.getRepeatedForeignEnumList());
+    assertIsUnmodifiable(value.getRepeatedImportEnumList());
+  }
+
+  private void assertIsUnmodifiable(List<?> list) {
+    if (list == Collections.emptyList()) {
+      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
+    } else {
+      try {
+        list.clear();
+        fail("List wasn't immutable");
+      } catch (UnsupportedOperationException e) {
+        // good
+      }
+    }
+  }
+
+  public void testSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      builder.setOptionalString(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalBytes(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedMessage(
+          (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedEnum(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedString(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedBytes(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedMessage(
+          (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedEnum(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testRepeatedSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestUtil.modifyRepeatedFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertRepeatedFieldsModified(message);
+  }
+
+  public void testRepeatedSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    builder.addRepeatedString("one");
+    builder.addRepeatedString("two");
+    try {
+      builder.setRepeatedString(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedBytes(TestUtil.toBytes("one"));
+    builder.addRepeatedBytes(TestUtil.toBytes("two"));
+    try {
+      builder.setRepeatedBytes(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    builder.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(456).build());
+    try {
+      builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setRepeatedNestedMessage(
+          1, (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.FOO);
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
+    try {
+      builder.setRepeatedNestedEnum(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testRepeatedAppend() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
+    builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+
+    ForeignMessage foreignMessage =
+        ForeignMessage.newBuilder().setC(12).build();
+    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());
+  }
+
+  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");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedForeignEnum(
+          Arrays.asList(ForeignEnum.FOREIGN_BAZ, null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedString(Arrays.asList("one", null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testSettingForeignMessageUsingBuilder() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        // Pass builder for foreign message instance.
+        .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123))
+        .build();
+    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+        // Create expected version passing foreign message instance explicitly.
+        .setOptionalForeignMessage(
+            ForeignMessage.newBuilder().setC(123).build())
+        .build();
+    // TODO(ngd): Upgrade to using real #equals method once implemented
+    assertEquals(expectedMessage.toString(), message.toString());
+  }
+
+  public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        // Pass builder for foreign message instance.
+        .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456))
+        .build();
+    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+        // Create expected version passing foreign message instance explicitly.
+        .addRepeatedForeignMessage(
+            ForeignMessage.newBuilder().setC(456).build())
+        .build();
+    assertEquals(expectedMessage.toString(), message.toString());
+  }
+
+  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());
+    assertEquals(Double.NEGATIVE_INFINITY, message.getNegInfDouble());
+    assertTrue(Double.isNaN(message.getNanDouble()));
+    assertEquals(Float.POSITIVE_INFINITY, message.getInfFloat());
+    assertEquals(Float.NEGATIVE_INFINITY, message.getNegInfFloat());
+    assertTrue(Float.isNaN(message.getNanFloat()));
+    assertEquals("? ? ?? ?? ??? ??/ ??-", message.getCppTrigraph());
+  }
+
+  public void testClear() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.assertClear(builder);
+    TestUtil.setAllFields(builder);
+    builder.clear();
+    TestUtil.assertClear(builder);
+  }
+
+  public void testReflectionGetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    reflectionTester.assertAllFieldsSetViaReflection(builder);
+
+    TestAllTypes message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testReflectionSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    TestUtil.assertAllFieldsSet(builder);
+
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+  }
+
+  public void testReflectionSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testReflectionRepeatedSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    TestUtil.assertRepeatedFieldsModified(builder);
+
+    TestAllTypes message = builder.build();
+    TestUtil.assertRepeatedFieldsModified(message);
+  }
+
+  public void testReflectionRepeatedSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+  }
+
+  public void testReflectionDefaults() throws Exception {
+    reflectionTester.assertClearViaReflection(
+      TestAllTypes.getDefaultInstance());
+    reflectionTester.assertClearViaReflection(
+      TestAllTypes.newBuilder().build());
+  }
+
+  public void testEnumInterface() throws Exception {
+    assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
+        instanceof ProtocolMessageEnum);
+  }
+
+  public void testEnumMap() throws Exception {
+    Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
+
+    for (ForeignEnum value : ForeignEnum.values()) {
+      assertEquals(value, map.findValueByNumber(value.getNumber()));
+    }
+
+    assertTrue(map.findValueByNumber(12345) == null);
+  }
+
+  public void testParsePackedToUnpacked() throws Exception {
+    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
+    TestUnpackedTypes message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(message);
+  }
+
+  public void testParseUnpackedToPacked() throws Exception {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    TestPackedTypes message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet(message);
+  }
+
+  // =================================================================
+  // Extensions.
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+
+  public void testExtensionMessageOrBuilder() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestAllExtensions message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testExtensionRepeatedSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestUtil.modifyRepeatedExtensions(builder);
+    TestAllExtensions message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testExtensionDefaults() throws Exception {
+    TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
+    TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
+  }
+
+  public void testExtensionReflectionGetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(builder);
+
+    TestAllExtensions message = builder.build();
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testExtensionReflectionSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    TestUtil.assertAllExtensionsSet(builder);
+
+    TestAllExtensions message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testExtensionReflectionSettersRejectNull() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testExtensionReflectionRepeatedSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    extensionsReflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    TestUtil.assertRepeatedExtensionsModified(builder);
+
+    TestAllExtensions message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testExtensionReflectionRepeatedSettersRejectNull()
+      throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull(
+        builder);
+  }
+
+  public void testExtensionReflectionDefaults() throws Exception {
+    extensionsReflectionTester.assertClearViaReflection(
+      TestAllExtensions.getDefaultInstance());
+    extensionsReflectionTester.assertClearViaReflection(
+      TestAllExtensions.newBuilder().build());
+  }
+
+  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));
+  }
+
+  public void testExtensionCopy() throws Exception {
+    TestAllExtensions original = TestUtil.getAllExtensionsSet();
+    TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
+    TestUtil.assertAllExtensionsSet(copy);
+  }
+
+  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));
+  }
+
+  // =================================================================
+  // multiple_files_test
+
+  public void testMultipleFilesOption() throws Exception {
+    // We mostly just want to check that things compile.
+    MessageWithNoOuter message =
+      MessageWithNoOuter.newBuilder()
+        .setNested(MessageWithNoOuter.NestedMessage.newBuilder().setI(1))
+        .addForeign(TestAllTypes.newBuilder().setOptionalInt32(1))
+        .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
+        .setForeignEnum(EnumWithNoOuter.BAR)
+        .build();
+    assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
+
+    assertEquals(MultipleFilesTestProto.getDescriptor(),
+                 MessageWithNoOuter.getDescriptor().getFile());
+
+    Descriptors.FieldDescriptor field =
+      MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
+    assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(),
+                 message.getField(field));
+
+    assertEquals(MultipleFilesTestProto.getDescriptor(),
+                 ServiceWithNoOuter.getDescriptor().getFile());
+
+    assertFalse(
+      TestAllExtensions.getDefaultInstance().hasExtension(
+        MultipleFilesTestProto.extensionWithOuter));
+  }
+
+  public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize()
+    throws Exception {
+    TestOptionalOptimizedForSize message =
+        TestOptionalOptimizedForSize.getDefaultInstance();
+    assertTrue(message.isInitialized());
+
+    message = TestOptionalOptimizedForSize.newBuilder().setO(
+        TestRequiredOptimizedForSize.newBuilder().buildPartial()
+        ).buildPartial();
+    assertFalse(message.isInitialized());
+
+    message = TestOptionalOptimizedForSize.newBuilder().setO(
+        TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial()
+        ).buildPartial();
+    assertTrue(message.isInitialized());
+  }
+
+  public void testUninitializedExtensionInOptimizedForSize()
+      throws Exception {
+    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().buildPartial());
+    assertFalse(builder.isInitialized());
+    assertFalse(builder.buildPartial().isInitialized());
+
+    builder = TestOptimizedForSize.newBuilder();
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().setX(10).buildPartial());
+    assertTrue(builder.isInitialized());
+    assertTrue(builder.buildPartial().isInitialized());
+  }
+
+  public void testToBuilder() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+    TestUtil.assertAllFieldsSet(message.toBuilder().build());
+  }
+
+  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);
+  }
+
+  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);
+  }
+
+  public void testRecursiveMessageDefaultInstance() throws Exception {
+    UnittestProto.TestRecursiveMessage message =
+        UnittestProto.TestRecursiveMessage.getDefaultInstance();
+    assertTrue(message != null);
+    assertTrue(message.getA() != null);
+    assertTrue(message.getA() == message);
+  }
+
+  public void testSerialize() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes expected = builder.build();
+    ObjectOutputStream out = new ObjectOutputStream(baos);
+    try {
+      out.writeObject(expected);
+    } finally {
+      out.close();
+    }
+    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+    ObjectInputStream in = new ObjectInputStream(bais);
+    TestAllTypes actual = (TestAllTypes) in.readObject();
+    assertEquals(expected, actual);
+  }
+
+  public void testSerializePartial() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes expected = builder.buildPartial();
+    ObjectOutputStream out = new ObjectOutputStream(baos);
+    try {
+      out.writeObject(expected);
+    } finally {
+      out.close();
+    }
+    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+    ObjectInputStream in = new ObjectInputStream(bais);
+    TestAllTypes actual = (TestAllTypes) in.readObject();
+    assertEquals(expected, actual);
+  }
+
+  public void testEnumValues() {
+     assertEquals(
+         TestAllTypes.NestedEnum.BAR.getNumber(),
+         TestAllTypes.NestedEnum.BAR_VALUE);
+    assertEquals(
+        TestAllTypes.NestedEnum.BAZ.getNumber(),
+        TestAllTypes.NestedEnum.BAZ_VALUE);
+    assertEquals(
+        TestAllTypes.NestedEnum.FOO.getNumber(),
+        TestAllTypes.NestedEnum.FOO_VALUE);
+  }
+
+  public void testNonNestedExtensionInitialization() {
+    assertTrue(NonNestedExtension.nonNestedExtension
+               .getMessageDefaultInstance() instanceof MyNonNestedExtension);
+    assertEquals("nonNestedExtension",
+                 NonNestedExtension.nonNestedExtension.getDescriptor().getName());
+  }
+
+  public void testNestedExtensionInitialization() {
+    assertTrue(MyNestedExtension.recursiveExtension.getMessageDefaultInstance()
+               instanceof MessageToBeExtended);
+    assertEquals("recursiveExtension",
+                 MyNestedExtension.recursiveExtension.getDescriptor().getName());
+  }
+
+
+  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 builderAsInterface = (TestAllTypesOrBuilder) builder;
+    TestAllTypesOrBuilder messageAsInterface = (TestAllTypesOrBuilder) message;
+
+    assertEquals(
+        messageAsInterface.getDefaultBool(),
+        messageAsInterface.getDefaultBool());
+    assertEquals(
+        messageAsInterface.getOptionalDouble(),
+        messageAsInterface.getOptionalDouble());
+  }
+
+  public void testMessageOrBuilderGetters() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    // single fields
+    assertSame(ForeignMessage.getDefaultInstance(),
+        builder.getOptionalForeignMessageOrBuilder());
+    ForeignMessage.Builder subBuilder =
+        builder.getOptionalForeignMessageBuilder();
+    assertSame(subBuilder, builder.getOptionalForeignMessageOrBuilder());
+
+    // repeated fields
+    ForeignMessage m0 = ForeignMessage.newBuilder().buildPartial();
+    ForeignMessage m1 = ForeignMessage.newBuilder().buildPartial();
+    ForeignMessage m2 = ForeignMessage.newBuilder().buildPartial();
+    builder.addRepeatedForeignMessage(m0);
+    builder.addRepeatedForeignMessage(m1);
+    builder.addRepeatedForeignMessage(m2);
+    assertSame(m0, builder.getRepeatedForeignMessageOrBuilder(0));
+    assertSame(m1, builder.getRepeatedForeignMessageOrBuilder(1));
+    assertSame(m2, 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));
+
+    List<? extends ForeignMessageOrBuilder> messageOrBuilderList =
+        builder.getRepeatedForeignMessageOrBuilderList();
+    assertSame(b0, messageOrBuilderList.get(0));
+    assertSame(b1, messageOrBuilderList.get(1));
+    assertSame(m2, messageOrBuilderList.get(2));
+  }
+
+  public void testGetFieldBuilder() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("optional_nested_message");
+    FieldDescriptor foreignFieldDescriptor =
+        descriptor.findFieldByName("optional_foreign_message");
+    FieldDescriptor importFieldDescriptor =
+        descriptor.findFieldByName("optional_import_message");
+
+    // Mutate the message with new field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
+    Message.Builder fieldBuilder1 = builder1.newBuilderForField(fieldDescriptor)
+        .mergeFrom((Message) builder1.getField(fieldDescriptor));
+    FieldDescriptor subFieldDescriptor1 =
+        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder1.setField(subFieldDescriptor1, 1);
+    builder1.setField(fieldDescriptor, fieldBuilder1.build());
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField(
+        foreignFieldDescriptor)
+        .mergeFrom((Message) builder1.getField(foreignFieldDescriptor));
+    FieldDescriptor subForeignFieldDescriptor1 =
+        foreignFieldBuilder1.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2);
+    builder1.setField(foreignFieldDescriptor, foreignFieldBuilder1.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder1 = builder1.newBuilderForField(
+        importFieldDescriptor)
+        .mergeFrom((Message) builder1.getField(importFieldDescriptor));
+    FieldDescriptor subImportFieldDescriptor1 =
+        importFieldBuilder1.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder1.setField(subImportFieldDescriptor1, 3);
+    builder1.setField(importFieldDescriptor, importFieldBuilder1.build());
+
+    Message newMessage1 = builder1.build();
+
+    // Mutate the message with existing field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
+    Message.Builder fieldBuilder2 = builder2.getFieldBuilder(fieldDescriptor);
+    FieldDescriptor subFieldDescriptor2 =
+        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder2.setField(subFieldDescriptor2, 1);
+    builder2.setField(fieldDescriptor, fieldBuilder2.build());
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(
+        foreignFieldDescriptor)
+        .mergeFrom((Message) builder2.getField(foreignFieldDescriptor));
+    FieldDescriptor subForeignFieldDescriptor2 =
+        foreignFieldBuilder2.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2);
+    builder2.setField(foreignFieldDescriptor, foreignFieldBuilder2.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder2 = builder2.newBuilderForField(
+        importFieldDescriptor)
+        .mergeFrom((Message) builder2.getField(importFieldDescriptor));
+    FieldDescriptor subImportFieldDescriptor2 =
+        importFieldBuilder2.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder2.setField(subImportFieldDescriptor2, 3);
+    builder2.setField(importFieldDescriptor, importFieldBuilder2.build());
+
+    Message newMessage2 = builder2.build();
+
+    // These two messages should be equal.
+    assertEquals(newMessage1, newMessage2);
+  }
+
+  public void testGetFieldBuilderWithInitializedValue() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("optional_nested_message");
+
+    // Before setting field, builder is initialized by default value. 
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    NestedMessage.Builder fieldBuilder =
+        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+    assertEquals(0, fieldBuilder.getBb());
+
+    // Setting field value with new field builder instance.
+    builder = TestAllTypes.newBuilder();
+    NestedMessage.Builder newFieldBuilder =
+        builder.getOptionalNestedMessageBuilder();
+    newFieldBuilder.setBb(2);
+    // Then get the field builder instance by getFieldBuilder().
+    fieldBuilder =
+        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+    // It should contain new value.
+    assertEquals(2, fieldBuilder.getBb());
+    // These two builder should be equal.
+    assertSame(fieldBuilder, newFieldBuilder);
+  }
+
+  public void testGetFieldBuilderNotSupportedException() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      builder.getFieldBuilder(descriptor.findFieldByName("optional_int32"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("optional_nested_enum"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(descriptor.findFieldByName("repeated_int32"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("repeated_nested_enum"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("repeated_nested_message"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringArrayListTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringArrayListTest.java
new file mode 100644
index 0000000..9bc94ee
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringArrayListTest.java
@@ -0,0 +1,163 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link LazyStringArrayList}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class LazyStringArrayListTest extends TestCase {
+
+  private static String STRING_A = "A";
+  private static String STRING_B = "B";
+  private static String STRING_C = "C";
+
+  private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
+  private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
+  private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
+
+  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));
+
+    list.set(1, STRING_C);
+    assertSame(STRING_C, list.get(1));
+
+    list.remove(1);
+    assertSame(STRING_A, list.get(0));
+    assertSame(STRING_C, list.get(1));
+  }
+
+  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));
+
+    list.remove(1);
+    assertSame(BYTE_STRING_A, list.getByteString(0));
+    assertSame(BYTE_STRING_C, list.getByteString(1));
+  }
+
+  public void testConversionBackAndForth() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.add(BYTE_STRING_B);
+    list.add(BYTE_STRING_C);
+
+    // String a should be the same because it was originally a string
+    assertSame(STRING_A, list.get(0));
+
+    // 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);
+    String cPrime = list.get(2);
+    assertNotSame(STRING_C, cPrime);
+    assertEquals(STRING_C, cPrime);
+
+    // String c and c should stay the same once cached.
+    assertSame(bPrime, list.get(1));
+    assertSame(cPrime, list.get(2));
+
+    // ByteString needs to be computed from string for both a and b
+    ByteString aPrimeByteString = list.getByteString(0);
+    assertEquals(BYTE_STRING_A, aPrimeByteString);
+    ByteString bPrimeByteString = list.getByteString(1);
+    assertNotSame(BYTE_STRING_B, bPrimeByteString);
+    assertEquals(BYTE_STRING_B, list.getByteString(1));
+
+    // Once cached, ByteString should stay cached.
+    assertSame(aPrimeByteString, list.getByteString(0));
+    assertSame(bPrimeByteString, list.getByteString(1));
+  }
+
+  public void testCopyConstructorCopiesByReference() {
+    LazyStringArrayList list1 = new LazyStringArrayList();
+    list1.add(STRING_A);
+    list1.add(BYTE_STRING_B);
+    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));
+  }
+
+  public void testListCopyConstructor() {
+    List<String> list1 = new ArrayList<String>();
+    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));
+  }
+
+  public void testAddAllCopiesByReferenceIfPossible() {
+    LazyStringArrayList list1 = new LazyStringArrayList();
+    list1.add(STRING_A);
+    list1.add(BYTE_STRING_B);
+    list1.add(BYTE_STRING_C);
+
+    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));
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringEndToEndTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringEndToEndTest.java
new file mode 100644
index 0000000..e21e038
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LazyStringEndToEndTest.java
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+
+import protobuf_unittest.UnittestProto;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
+ * strings works correctly.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class LazyStringEndToEndTest extends TestCase {
+
+  private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
+      ByteString.copyFrom(new byte[] {
+          114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
+          0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
+
+  private ByteString encodedTestAllTypes;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
+        .setOptionalString("foo")
+        .addRepeatedString("bar")
+        .addRepeatedString("baz")
+        .build()
+        .toByteString();
+  }
+
+  /**
+   * Tests that an invalid UTF8 string will roundtrip through a parse
+   * and serialization.
+   */
+  public void testParseAndSerialize() throws InvalidProtocolBufferException {
+    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
+        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+    ByteString bytes = tV2.toByteString();
+    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+
+    tV2.getOptionalString();
+    bytes = tV2.toByteString();
+    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+  }
+
+  public void testParseAndWrite() throws IOException {
+    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
+        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+    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));
+  }
+
+  public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
+    UnittestProto.TestAllTypes proto =
+        UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
+    ByteString optional = proto.getOptionalStringBytes();
+    assertSame(optional, proto.getOptionalStringBytes());
+    assertSame(optional, proto.toBuilder().getOptionalStringBytes());
+
+    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));
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LiteralByteStringTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LiteralByteStringTest.java
new file mode 100644
index 0000000..b2dcc7e
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/LiteralByteStringTest.java
@@ -0,0 +1,344 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
+ * This class is designed to be extended for testing extensions of {@link LiteralByteString}
+ * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class LiteralByteStringTest extends TestCase {
+  protected static final String UTF_8 = "UTF-8";
+
+  protected String classUnderTest;
+  protected byte[] referenceBytes;
+  protected ByteString stringUnderTest;
+  protected int expectedHashCode;
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "LiteralByteString";
+    referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
+    stringUnderTest = ByteString.copyFrom(referenceBytes);
+    expectedHashCode = 331161852;
+  }
+
+  protected String getActualClassName(Object object) {
+    String actualClassName = object.getClass().getName();
+    actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
+    return actualClassName;
+  }
+
+  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);
+  }
+
+  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 itertor", iter.hasNext());
+
+    try {
+      iter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+  }
+
+  public void testByteIterable() {
+    boolean stillEqual = true;
+    int j = 0;
+    for (byte quantum : stringUnderTest) {
+      stillEqual = (referenceBytes[j] == quantum);
+      ++j;
+    }
+    assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
+    assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
+  }
+
+  public void testSize() {
+    assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
+        stringUnderTest.size());
+  }
+
+  public void testCopyTo_ByteArrayOffsetLength() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+    int sourceOffset = 213;
+    stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length);
+    boolean stillEqual = true;
+    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);
+  }
+
+  public void testCopyTo_ByteArrayOffsetLengthErrors() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+
+    try {
+      // 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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    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);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+  }
+
+  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()));
+  }
+
+  public void testAsReadOnlyByteBuffer() {
+    ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
+    byte[] roundTripBytes = new byte[referenceBytes.length];
+    assertTrue(byteBuffer.remaining() == referenceBytes.length);
+    assertTrue(byteBuffer.isReadOnly());
+    byteBuffer.get(roundTripBytes);
+    assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  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);
+      byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
+      bytesSeen += thisLength;
+    }
+    assertTrue(bytesSeen == referenceBytes.length);
+    assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  public void testToByteArray() {
+    byte[] roundTripBytes = stringUnderTest.toByteArray();
+    assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  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));
+  }
+  
+  public void testWriteTo_mutating() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        for (int x = 0; x < len; ++x) {
+          b[off + x] = (byte) 0;
+        }
+      }
+
+      @Override
+      public void write(int b) {
+        // Purposefully left blank.
+      }
+    };
+
+    stringUnderTest.writeTo(os);
+    byte[] newBytes = stringUnderTest.toByteArray();
+    assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
+        Arrays.equals(referenceBytes, newBytes));
+  }
+
+  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());
+    output.writeTo(bos);
+    assertTrue("Output.writeTo() must give back the same bytes",
+        Arrays.equals(referenceBytes, bos.toByteArray()));
+
+    // 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());
+
+    output.reset();
+    assertEquals("Output.reset() resets the output", 0, output.size());
+    assertEquals("Output.reset() resets the output",
+        ByteString.EMPTY, output.toByteString());
+    
+  }
+
+  public void testHashCode() {
+    int hash = stringUnderTest.hashCode();
+    assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
+  }
+
+  public void testNewInput() throws IOException {
+    InputStream input = stringUnderTest.newInput();
+    assertEquals("InputStream.available() returns correct value",
+        stringUnderTest.size(), 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());
+  }
+
+  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());
+    input.mark(0);
+    assertEquals("InputStream.skip(), read()",
+        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertEquals("InputStream.available()",
+                 stringSize - skipped1 - 1, input.available());
+    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());
+    input.reset();
+    assertEquals("InputStream.reset() succeded",
+                 stringSize - skipped1, input.available());
+    assertEquals("InputStream.reset(), read()",
+        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+  }
+
+  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());
+  }
+
+  /**
+   * Make sure we keep things simple when concatenating with empty. See also
+   * {@link ByteStringTest#testConcat_empty()}.
+   */
+  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);
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/MessageTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/MessageTest.java
new file mode 100644
index 0000000..c8c95a8
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/MessageTest.java
@@ -0,0 +1,354 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Misc. unit tests for message operations that apply to both generated
+ * and dynamic messages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class MessageTest extends TestCase {
+  // =================================================================
+  // Message-merging tests.
+
+  static final TestAllTypes MERGE_SOURCE =
+    TestAllTypes.newBuilder()
+      .setOptionalInt32(1)
+      .setOptionalString("foo")
+      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+      .addRepeatedString("bar")
+      .build();
+
+  static final TestAllTypes MERGE_DEST =
+    TestAllTypes.newBuilder()
+      .setOptionalInt64(2)
+      .setOptionalString("baz")
+      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+      .addRepeatedString("qux")
+      .build();
+
+  static final String MERGE_RESULT_TEXT =
+      "optional_int32: 1\n" +
+      "optional_int64: 2\n" +
+      "optional_string: \"foo\"\n" +
+      "optional_foreign_message {\n" +
+      "  c: 3\n" +
+      "}\n" +
+      "repeated_string: \"qux\"\n" +
+      "repeated_string: \"bar\"\n";
+
+  public void testMergeFrom() throws Exception {
+    TestAllTypes result =
+      TestAllTypes.newBuilder(MERGE_DEST)
+        .mergeFrom(MERGE_SOURCE).build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  /**
+   * 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.
+   */
+  public void testMergeFromDynamic() throws Exception {
+    TestAllTypes result =
+      TestAllTypes.newBuilder(MERGE_DEST)
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  /** Test merging two DynamicMessages. */
+  public void testDynamicMergeFrom() throws Exception {
+    DynamicMessage result =
+      DynamicMessage.newBuilder(MERGE_DEST)
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  // =================================================================
+  // Required-field-related tests.
+
+  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+    TestRequired.getDefaultInstance();
+  private static final TestRequired TEST_REQUIRED_INITIALIZED =
+    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+  public void testRequired() throws Exception {
+    TestRequired.Builder builder = TestRequired.newBuilder();
+
+    assertFalse(builder.isInitialized());
+    builder.setA(1);
+    assertFalse(builder.isInitialized());
+    builder.setB(1);
+    assertFalse(builder.isInitialized());
+    builder.setC(1);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredForeign() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+
+    assertTrue(builder.isInitialized());
+
+    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredExtension() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+
+    assertTrue(builder.isInitialized());
+
+    builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredDynamic() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("a"), 1);
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("b"), 1);
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("c"), 1);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredDynamicForeign() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
+    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+    assertTrue(builder.isInitialized());
+
+    builder.setField(descriptor.findFieldByName("optional_message"),
+                     TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setField(descriptor.findFieldByName("optional_message"),
+                     TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
+                             TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
+                             TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testUninitializedException() throws Exception {
+    try {
+      TestRequired.newBuilder().build();
+      fail("Should have thrown an exception.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testBuildPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    TestRequired message = TestRequired.newBuilder().buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testNestedUninitializedException() throws Exception {
+    try {
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .build();
+      fail("Should have thrown an exception.");
+    } 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());
+    }
+  }
+
+  public void testBuildNestedPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    TestRequiredForeign message =
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testParseUnititialized() throws Exception {
+    try {
+      TestRequired.parseFrom(ByteString.EMPTY);
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testParseNestedUnititialized() throws Exception {
+    ByteString data =
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .buildPartial().toByteString();
+
+    try {
+      TestRequiredForeign.parseFrom(data);
+      fail("Should have thrown an exception.");
+    } 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());
+    }
+  }
+
+  public void testDynamicUninitializedException() throws Exception {
+    try {
+      DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
+      fail("Should have thrown an exception.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testDynamicBuildPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    DynamicMessage message =
+      DynamicMessage.newBuilder(TestRequired.getDescriptor())
+        .buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testDynamicParseUnititialized() throws Exception {
+    try {
+      Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+      DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+  
+  /** Test reading unset repeated message from DynamicMessage. */
+  public void testDynamicRepeatedMessageNull() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage result =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertTrue(result.getField(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")), 0);
+  }
+  
+  /** Test reading repeated message from DynamicMessage. */
+  public void testDynamicRepeatedMessageNotNull() throws Exception {
+
+    TestAllTypes REPEATED_NESTED =
+      TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("foo")
+        .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+        .addRepeatedString("bar")
+        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+        .build();
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage result =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+        .mergeFrom(DynamicMessage.newBuilder(REPEATED_NESTED).build())
+        .build();
+
+    assertTrue(result.getField(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")), 2);
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/NestedBuildersTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/NestedBuildersTest.java
new file mode 100644
index 0000000..68d70be
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/NestedBuildersTest.java
@@ -0,0 +1,186 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.Vehicle;
+import protobuf_unittest.Wheel;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Test cases that exercise end-to-end use cases involving
+ * {@link SingleFieldBuilder} and {@link RepeatedFieldBuilder}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class NestedBuildersTest extends TestCase {
+
+  public void testMessagesAndBuilders() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(1);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(2);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(3);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(4);
+    vehicleBuilder.getEngineBuilder()
+        .setLiters(10);
+
+    Vehicle vehicle = vehicleBuilder.build();
+    assertEquals(4, vehicle.getWheelCount());
+    for (int i = 0; i < 4; i++) {
+      Wheel wheel = vehicle.getWheel(i);
+      assertEquals(4, wheel.getRadius());
+      assertEquals(i + 1, wheel.getWidth());
+    }
+    assertEquals(10, vehicle.getEngine().getLiters());
+
+    for (int i = 0; i < 4; i++) {
+      vehicleBuilder.getWheelBuilder(i)
+          .setRadius(5)
+          .setWidth(i + 10);
+    }
+    vehicleBuilder.getEngineBuilder().setLiters(20);
+
+    vehicle = vehicleBuilder.build();
+    for (int i = 0; i < 4; i++) {
+      Wheel wheel = vehicle.getWheel(i);
+      assertEquals(5, wheel.getRadius());
+      assertEquals(i + 10, wheel.getWidth());
+    }
+    assertEquals(20, vehicle.getEngine().getLiters());
+    assertTrue(vehicle.hasEngine());
+  }
+
+  public void testMessagesAreCached() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(1)
+        .setWidth(2);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(3)
+        .setWidth(4);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(5)
+        .setWidth(6);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(7)
+        .setWidth(8);
+
+    // 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));
+    }
+
+    // Now get builders and check they didn't change.
+    for (int i = 0; i < wheels.size(); i++) {
+      vehicleBuilder.getWheel(i);
+    }
+    for (int i = 0; i < wheels.size(); i++) {
+      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+    }
+
+    // Change just one
+    vehicleBuilder.getWheelBuilder(3)
+        .setRadius(20).setWidth(20);
+
+    // 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));
+      } else {
+        assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i));
+      }
+    }
+  }
+
+  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());
+  }
+
+  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());
+  }
+
+  public void testMerge() {
+    Vehicle vehicle1 = Vehicle.newBuilder()
+        .addWheel(Wheel.newBuilder().setRadius(1).build())
+        .addWheel(Wheel.newBuilder().setRadius(2).build())
+        .build();
+
+    Vehicle vehicle2 = Vehicle.newBuilder()
+        .mergeFrom(vehicle1)
+        .build();
+    // List should be the same -- no allocation
+    assertSame(vehicle1.getWheelList(), vehicle2.getWheelList());
+
+    Vehicle vehicle3 = vehicle1.toBuilder().build();
+    assertSame(vehicle1.getWheelList(), vehicle3.getWheelList());
+  }
+
+  public void testGettingBuilderMarksFieldAsHaving() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.getEngineBuilder();
+    Vehicle vehicle = vehicleBuilder.buildPartial();
+    assertTrue(vehicle.hasEngine());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ParserTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ParserTest.java
new file mode 100644
index 0000000..b35af68
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ParserTest.java
@@ -0,0 +1,278 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestParsingMerge;
+import protobuf_unittest.UnittestProto;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit test for {@link Parser}.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public class ParserTest extends TestCase {
+  public void testGeneratedMessageParserSingleton() throws Exception {
+    for (int i = 0; i < 10; i++) {
+      assertEquals(TestAllTypes.PARSER,
+                   TestUtil.getAllSet().getParserForType());
+    }
+  }
+
+  private void assertRoundTripEquals(MessageLite message,
+                                     ExtensionRegistryLite registry)
+      throws Exception {
+    final byte[] data = message.toByteArray();
+    final int offset = 20;
+    final int length = data.length;
+    final int padding = 30;
+    Parser<? extends MessageLite> parser = message.getParserForType();
+    assertMessageEquals(message, parser.parseFrom(data, registry));
+    assertMessageEquals(message, parser.parseFrom(
+        generatePaddingArray(data, offset, padding),
+        offset, length, registry));
+    assertMessageEquals(message, parser.parseFrom(
+        message.toByteString(), registry));
+    assertMessageEquals(message, parser.parseFrom(
+        new ByteArrayInputStream(data), registry));
+    assertMessageEquals(message, parser.parseFrom(
+        CodedInputStream.newInstance(data), registry));
+  }
+
+  private void assertRoundTripEquals(MessageLite message) throws Exception {
+    final byte[] data = message.toByteArray();
+    final int offset = 20;
+    final int length = data.length;
+    final int padding = 30;
+    Parser<? extends MessageLite> parser = message.getParserForType();
+    assertMessageEquals(message, parser.parseFrom(data));
+    assertMessageEquals(message, parser.parseFrom(
+        generatePaddingArray(data, offset, padding),
+        offset, length));
+    assertMessageEquals(message, parser.parseFrom(message.toByteString()));
+    assertMessageEquals(message, parser.parseFrom(
+        new ByteArrayInputStream(data)));
+    assertMessageEquals(message, parser.parseFrom(
+        CodedInputStream.newInstance(data)));
+  }
+
+  private void assertMessageEquals(MessageLite expected, MessageLite actual)
+      throws Exception {
+    if (expected instanceof Message) {
+      assertEquals(expected, actual);
+    } else {
+      assertEquals(expected.toByteString(), actual.toByteString());
+    }
+  }
+
+  private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
+    byte[] result = new byte[offset + data.length + padding];
+    System.arraycopy(data, 0, result, offset, data.length);
+    return result;
+  }
+
+  public void testNormalMessage() throws Exception {
+    assertRoundTripEquals(TestUtil.getAllSet());
+  }
+
+  public void testParsePartial() throws Exception {
+    Parser<TestRequired> parser = TestRequired.PARSER;
+    final String errorString =
+        "Should throw exceptions when the parsed message isn't initialized.";
+
+    // TestRequired.b and TestRequired.c are not set.
+    TestRequired partialMessage = TestRequired.newBuilder()
+        .setA(1).buildPartial();
+
+    // 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)));
+
+    // parseFrom(ByteArray)
+    try {
+      parser.parseFrom(partialMessage.toByteArray());
+      fail(errorString);
+    } catch (InvalidProtocolBufferException e) {
+      // pass.
+    }
+
+    // parseFrom(ByteString)
+    try {
+      parser.parseFrom(partialMessage.toByteString());
+      fail(errorString);
+    } catch (InvalidProtocolBufferException e) {
+      // pass.
+    }
+
+    // parseFrom(InputStream)
+    try {
+      parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
+      fail(errorString);
+    } catch (IOException e) {
+      // pass.
+    }
+
+    // parseFrom(CodedInputStream)
+    try {
+      parser.parseFrom(CodedInputStream.newInstance(
+          partialMessage.toByteArray()));
+      fail(errorString);
+    } catch (IOException e) {
+      // pass.
+    }
+  }
+
+  public void testParseDelimitedTo() throws Exception {
+    // Write normal Message.
+    TestAllTypes normalMessage = TestUtil.getAllSet();
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    normalMessage.writeDelimitedTo(output);
+
+    InputStream input = new ByteArrayInputStream(output.toByteArray());
+    assertMessageEquals(
+        normalMessage,
+        normalMessage.getParserForType().parseDelimitedFrom(input));
+  }
+
+  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());
+  }
+
+  public void testOptimizeForSize() throws Exception {
+    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+    builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
+    builder.setExtension(TestOptimizedForSize.testExtension, 56);
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().setX(78).build());
+
+    TestOptimizedForSize message = builder.build();
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestOptimizeFor.registerAllExtensions(registry);
+
+    assertRoundTripEquals(message, registry);
+  }
+
+  /** Helper method for {@link #testParsingMerge()}.*/
+  private void assertMessageMerged(TestAllTypes allTypes)
+      throws Exception {
+    assertEquals(3, allTypes.getOptionalInt32());
+    assertEquals(2, allTypes.getOptionalInt64());
+    assertEquals("hello", allTypes.getOptionalString());
+  }
+
+  public void testParsingMerge() throws Exception {
+    // Build messages.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes msg1 = builder.setOptionalInt32(1).build();
+    builder.clear();
+    TestAllTypes msg2 = builder.setOptionalInt64(2).build();
+    builder.clear();
+    TestAllTypes msg3 = builder.setOptionalInt32(3)
+        .setOptionalString("hello").build();
+
+    // Build groups.
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg3).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg3).build();
+
+    // Assign and serialize RepeatedFieldsGenerator.
+    ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
+        .addField1(msg1).addField1(msg2).addField1(msg3)
+        .addField2(msg1).addField2(msg2).addField2(msg3)
+        .addField3(msg1).addField3(msg2).addField3(msg3)
+        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
+        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
+        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
+        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
+        .build().toByteString();
+
+    // Parse TestParsingMerge.
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestProto.registerAllExtensions(registry);
+    TestParsingMerge parsingMerge =
+        TestParsingMerge.PARSER.parseFrom(data, registry);
+
+    // Required and optional fields should be merged.
+    assertMessageMerged(parsingMerge.getRequiredAllTypes());
+    assertMessageMerged(parsingMerge.getOptionalAllTypes());
+    assertMessageMerged(
+        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+    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));
+  }
+
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringSubstringTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringSubstringTest.java
new file mode 100644
index 0000000..3c1f503
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringSubstringTest.java
@@ -0,0 +1,62 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from
+ * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.  
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringSubstringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "RopeByteString";
+    byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
+    ByteString sourceString = iter.next();
+    while (iter.hasNext()) {
+      sourceString = sourceString.concat(iter.next());
+    }
+
+    int from = 1130;
+    int to = sourceBytes.length - 5555;
+    stringUnderTest = sourceString.substring(from, to);
+    referenceBytes = new byte[to - from];
+    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+    expectedHashCode = -1259260680;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringTest.java
new file mode 100644
index 0000000..8caeadd
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RopeByteStringTest.java
@@ -0,0 +1,84 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString} by inheriting the tests from
+ * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.
+ * 
+ * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
+ * separate class {@link RopeByteStringSubstringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "RopeByteString";
+    referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
+    stringUnderTest = iter.next();
+    while (iter.hasNext()) {
+      stringUnderTest = stringUnderTest.concat(iter.next());
+    }
+    expectedHashCode = -1214197238;
+  }
+
+  public void testBalance() {
+    int numberOfPieces = 10000;
+    int pieceSize = 64;
+    byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L);
+
+    // Build up a big ByteString from smaller pieces to force a rebalance
+    ByteString concatenated = ByteString.EMPTY;
+    for (int i = 0; i < numberOfPieces; ++i) {
+      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()));
+    ByteString testString = ByteString.copyFrom(testBytes);
+    assertTrue(classUnderTest + " balanced string must equal flat string",
+        concatenated.equals(testString));
+    assertTrue(classUnderTest + " flat string must equal balanced string",
+        testString.equals(concatenated));
+    assertEquals(classUnderTest + " balanced string must have same hash code as flat string",
+        testString.hashCode(), concatenated.hashCode());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ServiceTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ServiceTest.java
new file mode 100644
index 0000000..4c7f751
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ServiceTest.java
@@ -0,0 +1,321 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.ServiceWithNoOuter;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestService;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.BarRequest;
+import protobuf_unittest.UnittestProto.BarResponse;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.easymock.IArgumentMatcher;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests services and stubs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ServiceTest extends TestCase {
+  private IMocksControl control;
+  private RpcController mockController;
+
+  private final Descriptors.MethodDescriptor fooDescriptor =
+    TestService.getDescriptor().getMethods().get(0);
+  private final Descriptors.MethodDescriptor barDescriptor =
+    TestService.getDescriptor().getMethods().get(1);
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    control = EasyMock.createStrictControl();
+    mockController = control.createMock(RpcController.class);
+  }
+
+  // =================================================================
+
+  /** Tests Service.callMethod(). */
+  public void testCallMethod() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    MockCallback<Message> fooCallback = new MockCallback<Message>();
+    MockCallback<Message> barCallback = new MockCallback<Message>();
+    TestService mockService = control.createMock(TestService.class);
+
+    mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
+                    this.<FooResponse>wrapsCallback(fooCallback));
+    mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
+                    this.<BarResponse>wrapsCallback(barCallback));
+    control.replay();
+
+    mockService.callMethod(fooDescriptor, mockController,
+                           fooRequest, fooCallback);
+    mockService.callMethod(barDescriptor, mockController,
+                           barRequest, barCallback);
+    control.verify();
+  }
+
+  /** Tests Service.get{Request,Response}Prototype(). */
+  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());
+  }
+
+  /** Tests generated stubs. */
+  public void testStub() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
+    MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
+    RpcChannel mockChannel = control.createMock(RpcChannel.class);
+    TestService stub = TestService.newStub(mockChannel);
+
+    mockChannel.callMethod(
+      EasyMock.same(fooDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(fooRequest),
+      EasyMock.same(FooResponse.getDefaultInstance()),
+      this.<Message>wrapsCallback(fooCallback));
+    mockChannel.callMethod(
+      EasyMock.same(barDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(barRequest),
+      EasyMock.same(BarResponse.getDefaultInstance()),
+      this.<Message>wrapsCallback(barCallback));
+    control.replay();
+
+    stub.foo(mockController, fooRequest, fooCallback);
+    stub.bar(mockController, barRequest, barCallback);
+    control.verify();
+  }
+
+  /** Tests generated blocking stubs. */
+  public void testBlockingStub() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    BlockingRpcChannel mockChannel =
+        control.createMock(BlockingRpcChannel.class);
+    TestService.BlockingInterface stub =
+        TestService.newBlockingStub(mockChannel);
+
+    FooResponse fooResponse = FooResponse.newBuilder().build();
+    BarResponse barResponse = BarResponse.newBuilder().build();
+
+    EasyMock.expect(mockChannel.callBlockingMethod(
+      EasyMock.same(fooDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(fooRequest),
+      EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
+    EasyMock.expect(mockChannel.callBlockingMethod(
+      EasyMock.same(barDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(barRequest),
+      EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
+    control.replay();
+
+    assertSame(fooResponse, stub.foo(mockController, fooRequest));
+    assertSame(barResponse, stub.bar(mockController, barRequest));
+    control.verify();
+  }
+
+  public void testNewReflectiveService() {
+    ServiceWithNoOuter.Interface impl =
+        control.createMock(ServiceWithNoOuter.Interface.class);
+    RpcController controller = control.createMock(RpcController.class);
+    Service service = ServiceWithNoOuter.newReflectiveService(impl);
+
+    MethodDescriptor fooMethod =
+        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+    RpcCallback<Message> callback = new RpcCallback<Message>() {
+      public void run(Message parameter) {
+        // No reason this should be run.
+        fail();
+      }
+    };
+    RpcCallback<TestAllTypes> specializedCallback =
+        RpcUtil.specializeCallback(callback);
+
+    impl.foo(EasyMock.same(controller), EasyMock.same(request),
+        EasyMock.same(specializedCallback));
+    EasyMock.expectLastCall();
+
+    control.replay();
+
+    service.callMethod(fooMethod, controller, request, callback);
+
+    control.verify();
+  }
+
+  public void testNewReflectiveBlockingService() throws ServiceException {
+    ServiceWithNoOuter.BlockingInterface impl =
+        control.createMock(ServiceWithNoOuter.BlockingInterface.class);
+    RpcController controller = control.createMock(RpcController.class);
+    BlockingService service =
+        ServiceWithNoOuter.newReflectiveBlockingService(impl);
+
+    MethodDescriptor fooMethod =
+        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+
+    TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
+    EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
+        .andReturn(expectedResponse);
+
+    control.replay();
+
+    Message response =
+        service.callBlockingMethod(fooMethod, controller, request);
+    assertEquals(expectedResponse, response);
+
+    control.verify();
+  }
+
+  public void testNoGenericServices() throws Exception {
+    // Non-services should be usable.
+    UnittestNoGenericServices.TestMessage message =
+      UnittestNoGenericServices.TestMessage.newBuilder()
+        .setA(123)
+        .setExtension(UnittestNoGenericServices.testExtension, 456)
+        .build();
+    assertEquals(123, message.getA());
+    assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
+
+    // Build a list of the class names nested in UnittestNoGenericServices.
+    String outerName = "google.protobuf.no_generic_services_test." +
+                       "UnittestNoGenericServices";
+    Class<?> outerClass = Class.forName(outerName);
+
+    Set<String> innerClassNames = new HashSet<String>();
+    for (Class<?> innerClass : outerClass.getClasses()) {
+      String fullName = innerClass.getName();
+      // Figure out the unqualified name of the inner class.
+      // Note:  Surprisingly, the full name of an inner class will be separated
+      //   from the outer class name by a '$' rather than a '.'.  This is not
+      //   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));
+
+      if (!Service.class.isAssignableFrom(innerClass) &&
+          !Message.class.isAssignableFrom(innerClass) &&
+          !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
+        // Ignore any classes not generated by the base code generator.
+        continue;
+      }
+
+      innerClassNames.add(fullName.substring(outerName.length() + 1));
+    }
+
+    // No service class should have been generated.
+    assertTrue(innerClassNames.contains("TestMessage"));
+    assertTrue(innerClassNames.contains("TestEnum"));
+    assertFalse(innerClassNames.contains("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());
+  }
+
+  // =================================================================
+
+  /**
+   * wrapsCallback() is an EasyMock argument predicate.  wrapsCallback(c)
+   * matches a callback if calling that callback causes c to be called.
+   * In other words, c wraps the given callback.
+   */
+  private <Type extends Message> RpcCallback<Type> wrapsCallback(
+      MockCallback<?> callback) {
+    EasyMock.reportMatcher(new WrapsCallback(callback));
+    return null;
+  }
+
+  /** The parameter to wrapsCallback() must be a MockCallback. */
+  private static class MockCallback<Type extends Message>
+      implements RpcCallback<Type> {
+    private boolean called = false;
+
+    public boolean isCalled() { return called; }
+
+    public void reset() { called = false; }
+    public void run(Type message) { called = true; }
+  }
+
+  /** Implementation of the wrapsCallback() argument matcher. */
+  private static class WrapsCallback implements IArgumentMatcher {
+    private MockCallback<?> callback;
+
+    public WrapsCallback(MockCallback<?> callback) {
+      this.callback = callback;
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean matches(Object actual) {
+      if (!(actual instanceof RpcCallback)) {
+        return false;
+      }
+      RpcCallback actualCallback = (RpcCallback)actual;
+
+      callback.reset();
+      actualCallback.run(null);
+      return callback.isCalled();
+    }
+
+    public void appendTo(StringBuffer buffer) {
+      buffer.append("wrapsCallback(mockCallback)");
+    }
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestBadIdentifiers.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestBadIdentifiers.java
new file mode 100644
index 0000000..5086732
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestBadIdentifiers.java
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that proto2 api generation doesn't cause compile errors when
+ * compiling protocol buffers that have names that would otherwise conflict
+ * if not fully qualified (like @Deprecated and @Override).
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class TestBadIdentifiers extends TestCase {
+
+  public void testCompilation() {
+    // If this compiles, it means the generation was correct.
+    TestBadIdentifiersProto.Deprecated.newBuilder();
+    TestBadIdentifiersProto.Override.newBuilder();
+  }
+
+  public void testGetDescriptor() {
+    Descriptors.FileDescriptor fileDescriptor =
+        TestBadIdentifiersProto.getDescriptor();
+    String descriptorField = TestBadIdentifiersProto.Descriptor
+        .getDefaultInstance().getDescriptor();
+    Descriptors.Descriptor protoDescriptor = TestBadIdentifiersProto.Descriptor
+        .getDefaultInstance().getDescriptorForType();
+    String nestedDescriptorField = TestBadIdentifiersProto.Descriptor
+        .NestedDescriptor.getDefaultInstance().getDescriptor();
+    Descriptors.Descriptor nestedProtoDescriptor = TestBadIdentifiersProto
+        .Descriptor.NestedDescriptor.getDefaultInstance()
+        .getDescriptorForType();
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestUtil.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestUtil.java
new file mode 100644
index 0000000..a923483
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TestUtil.java
@@ -0,0 +1,3068 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto;
+
+// The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
+// import static protobuf_unittest.UnittestProto.*;
+import static protobuf_unittest.UnittestProto.defaultInt32Extension;
+import static protobuf_unittest.UnittestProto.defaultInt64Extension;
+import static protobuf_unittest.UnittestProto.defaultUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint64Extension;
+import static protobuf_unittest.UnittestProto.defaultSint32Extension;
+import static protobuf_unittest.UnittestProto.defaultSint64Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultFloatExtension;
+import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
+import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultStringExtension;
+import static protobuf_unittest.UnittestProto.defaultBytesExtension;
+import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
+import static protobuf_unittest.UnittestProto.defaultCordExtension;
+
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+import static protobuf_unittest.UnittestProto.optionalUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalUint64Extension;
+import static protobuf_unittest.UnittestProto.optionalSint32Extension;
+import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalFloatExtension;
+import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
+import static protobuf_unittest.UnittestProto.optionalBoolExtension;
+import static protobuf_unittest.UnittestProto.optionalStringExtension;
+import static protobuf_unittest.UnittestProto.optionalBytesExtension;
+import static protobuf_unittest.UnittestProto.optionalGroupExtension;
+import static protobuf_unittest.UnittestProto.optionalCordExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
+
+import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
+import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
+import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
+import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringExtension;
+import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
+import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
+import static protobuf_unittest.UnittestProto.repeatedCordExtension;
+
+import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
+
+import static protobuf_unittest.UnittestProto.packedInt32Extension;
+import static protobuf_unittest.UnittestProto.packedInt64Extension;
+import static protobuf_unittest.UnittestProto.packedUint32Extension;
+import static protobuf_unittest.UnittestProto.packedUint64Extension;
+import static protobuf_unittest.UnittestProto.packedSint32Extension;
+import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.packedFixed32Extension;
+import static protobuf_unittest.UnittestProto.packedFixed64Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.packedFloatExtension;
+import static protobuf_unittest.UnittestProto.packedDoubleExtension;
+import static protobuf_unittest.UnittestProto.packedBoolExtension;
+import static protobuf_unittest.UnittestProto.packedEnumExtension;
+
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Contains methods for setting all fields of {@code TestAllTypes} to
+ * some values as well as checking that all the fields are set to those values.
+ * These are useful for testing various protocol message features, e.g.
+ * set all fields of a message, serialize it, parse it, and check that all
+ * fields are set.
+ *
+ * <p>This code is not to be used outside of {@code com.google.protobuf} and
+ * subpackages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class TestUtil {
+  private TestUtil() {}
+
+  /** Helper to convert a String to ByteString. */
+  static ByteString toBytes(String str) {
+    try {
+      return ByteString.copyFrom(str.getBytes("UTF-8"));
+    } catch(java.io.UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported.", e);
+    }
+  }
+
+  /**
+   * Get a {@code TestAllTypes} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}.
+   */
+  public static TestAllTypes getAllSet() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    setAllFields(builder);
+    return builder.build();
+  }
+
+  /**
+   * Get a {@code TestAllTypes.Builder} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}.
+   */
+  public static TestAllTypes.Builder getAllSetBuilder() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    setAllFields(builder);
+    return builder;
+  }
+
+  /**
+   * Get a {@code TestAllExtensions} with all fields set as they would be by
+   * {@link #setAllExtensions(TestAllExtensions.Builder)}.
+   */
+  public static TestAllExtensions getAllExtensionsSet() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    setAllExtensions(builder);
+    return builder.build();
+  }
+
+  public static TestPackedTypes getPackedSet() {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    setPackedFields(builder);
+    return builder.build();
+  }
+
+  public static TestUnpackedTypes getUnpackedSet() {
+    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
+    setUnpackedFields(builder);
+    return builder.build();
+  }
+
+  public static TestPackedExtensions getPackedExtensionsSet() {
+    TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder();
+    setPackedExtensions(builder);
+    return builder.build();
+  }
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllFieldsSet()}.
+   */
+  public static void setAllFields(TestAllTypes.Builder message) {
+    message.setOptionalInt32   (101);
+    message.setOptionalInt64   (102);
+    message.setOptionalUint32  (103);
+    message.setOptionalUint64  (104);
+    message.setOptionalSint32  (105);
+    message.setOptionalSint64  (106);
+    message.setOptionalFixed32 (107);
+    message.setOptionalFixed64 (108);
+    message.setOptionalSfixed32(109);
+    message.setOptionalSfixed64(110);
+    message.setOptionalFloat   (111);
+    message.setOptionalDouble  (112);
+    message.setOptionalBool    (true);
+    message.setOptionalString  ("115");
+    message.setOptionalBytes   (toBytes("116"));
+
+    message.setOptionalGroup(
+      TestAllTypes.OptionalGroup.newBuilder().setA(117).build());
+    message.setOptionalNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+    message.setOptionalForeignMessage(
+      ForeignMessage.newBuilder().setC(119).build());
+    message.setOptionalImportMessage(
+      ImportMessage.newBuilder().setD(120).build());
+    message.setOptionalPublicImportMessage(
+      PublicImportMessage.newBuilder().setE(126).build());
+    message.setOptionalLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
+    message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
+    message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
+
+    message.setOptionalStringPiece("124");
+    message.setOptionalCord("125");
+
+    // -----------------------------------------------------------------
+
+    message.addRepeatedInt32   (201);
+    message.addRepeatedInt64   (202);
+    message.addRepeatedUint32  (203);
+    message.addRepeatedUint64  (204);
+    message.addRepeatedSint32  (205);
+    message.addRepeatedSint64  (206);
+    message.addRepeatedFixed32 (207);
+    message.addRepeatedFixed64 (208);
+    message.addRepeatedSfixed32(209);
+    message.addRepeatedSfixed64(210);
+    message.addRepeatedFloat   (211);
+    message.addRepeatedDouble  (212);
+    message.addRepeatedBool    (true);
+    message.addRepeatedString  ("215");
+    message.addRepeatedBytes   (toBytes("216"));
+
+    message.addRepeatedGroup(
+      TestAllTypes.RepeatedGroup.newBuilder().setA(217).build());
+    message.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    message.addRepeatedForeignMessage(
+      ForeignMessage.newBuilder().setC(219).build());
+    message.addRepeatedImportMessage(
+      ImportMessage.newBuilder().setD(220).build());
+    message.addRepeatedLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
+    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
+    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAR);
+
+    message.addRepeatedStringPiece("224");
+    message.addRepeatedCord("225");
+
+    // Add a second one of each field.
+    message.addRepeatedInt32   (301);
+    message.addRepeatedInt64   (302);
+    message.addRepeatedUint32  (303);
+    message.addRepeatedUint64  (304);
+    message.addRepeatedSint32  (305);
+    message.addRepeatedSint64  (306);
+    message.addRepeatedFixed32 (307);
+    message.addRepeatedFixed64 (308);
+    message.addRepeatedSfixed32(309);
+    message.addRepeatedSfixed64(310);
+    message.addRepeatedFloat   (311);
+    message.addRepeatedDouble  (312);
+    message.addRepeatedBool    (false);
+    message.addRepeatedString  ("315");
+    message.addRepeatedBytes   (toBytes("316"));
+
+    message.addRepeatedGroup(
+      TestAllTypes.RepeatedGroup.newBuilder().setA(317).build());
+    message.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+    message.addRepeatedForeignMessage(
+      ForeignMessage.newBuilder().setC(319).build());
+    message.addRepeatedImportMessage(
+      ImportMessage.newBuilder().setD(320).build());
+    message.addRepeatedLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
+    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
+    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAZ);
+
+    message.addRepeatedStringPiece("324");
+    message.addRepeatedCord("325");
+
+    // -----------------------------------------------------------------
+
+    message.setDefaultInt32   (401);
+    message.setDefaultInt64   (402);
+    message.setDefaultUint32  (403);
+    message.setDefaultUint64  (404);
+    message.setDefaultSint32  (405);
+    message.setDefaultSint64  (406);
+    message.setDefaultFixed32 (407);
+    message.setDefaultFixed64 (408);
+    message.setDefaultSfixed32(409);
+    message.setDefaultSfixed64(410);
+    message.setDefaultFloat   (411);
+    message.setDefaultDouble  (412);
+    message.setDefaultBool    (false);
+    message.setDefaultString  ("415");
+    message.setDefaultBytes   (toBytes("416"));
+
+    message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
+    message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
+    message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
+
+    message.setDefaultStringPiece("424");
+    message.setDefaultCord("425");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated fields of {@code message} to contain the values
+   * expected by {@code assertRepeatedFieldsModified()}.
+   */
+  public static void modifyRepeatedFields(TestAllTypes.Builder message) {
+    message.setRepeatedInt32   (1, 501);
+    message.setRepeatedInt64   (1, 502);
+    message.setRepeatedUint32  (1, 503);
+    message.setRepeatedUint64  (1, 504);
+    message.setRepeatedSint32  (1, 505);
+    message.setRepeatedSint64  (1, 506);
+    message.setRepeatedFixed32 (1, 507);
+    message.setRepeatedFixed64 (1, 508);
+    message.setRepeatedSfixed32(1, 509);
+    message.setRepeatedSfixed64(1, 510);
+    message.setRepeatedFloat   (1, 511);
+    message.setRepeatedDouble  (1, 512);
+    message.setRepeatedBool    (1, true);
+    message.setRepeatedString  (1, "515");
+    message.setRepeatedBytes   (1, toBytes("516"));
+
+    message.setRepeatedGroup(1,
+      TestAllTypes.RepeatedGroup.newBuilder().setA(517).build());
+    message.setRepeatedNestedMessage(1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+    message.setRepeatedForeignMessage(1,
+      ForeignMessage.newBuilder().setC(519).build());
+    message.setRepeatedImportMessage(1,
+      ImportMessage.newBuilder().setD(520).build());
+    message.setRepeatedLazyMessage(1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
+    message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
+    message.setRepeatedImportEnum (1, ImportEnum.IMPORT_FOO);
+
+    message.setRepeatedStringPiece(1, "524");
+    message.setRepeatedCord(1, "525");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setAllFields}.
+   */
+  public static void assertAllFieldsSet(TestAllTypesOrBuilder message) {
+    Assert.assertTrue(message.hasOptionalInt32   ());
+    Assert.assertTrue(message.hasOptionalInt64   ());
+    Assert.assertTrue(message.hasOptionalUint32  ());
+    Assert.assertTrue(message.hasOptionalUint64  ());
+    Assert.assertTrue(message.hasOptionalSint32  ());
+    Assert.assertTrue(message.hasOptionalSint64  ());
+    Assert.assertTrue(message.hasOptionalFixed32 ());
+    Assert.assertTrue(message.hasOptionalFixed64 ());
+    Assert.assertTrue(message.hasOptionalSfixed32());
+    Assert.assertTrue(message.hasOptionalSfixed64());
+    Assert.assertTrue(message.hasOptionalFloat   ());
+    Assert.assertTrue(message.hasOptionalDouble  ());
+    Assert.assertTrue(message.hasOptionalBool    ());
+    Assert.assertTrue(message.hasOptionalString  ());
+    Assert.assertTrue(message.hasOptionalBytes   ());
+
+    Assert.assertTrue(message.hasOptionalGroup         ());
+    Assert.assertTrue(message.hasOptionalNestedMessage ());
+    Assert.assertTrue(message.hasOptionalForeignMessage());
+    Assert.assertTrue(message.hasOptionalImportMessage ());
+
+    Assert.assertTrue(message.getOptionalGroup         ().hasA());
+    Assert.assertTrue(message.getOptionalNestedMessage ().hasBb());
+    Assert.assertTrue(message.getOptionalForeignMessage().hasC());
+    Assert.assertTrue(message.getOptionalImportMessage ().hasD());
+
+    Assert.assertTrue(message.hasOptionalNestedEnum ());
+    Assert.assertTrue(message.hasOptionalForeignEnum());
+    Assert.assertTrue(message.hasOptionalImportEnum ());
+
+    Assert.assertTrue(message.hasOptionalStringPiece());
+    Assert.assertTrue(message.hasOptionalCord());
+
+    Assert.assertEquals(101  , message.getOptionalInt32   ());
+    Assert.assertEquals(102  , message.getOptionalInt64   ());
+    Assert.assertEquals(103  , message.getOptionalUint32  ());
+    Assert.assertEquals(104  , message.getOptionalUint64  ());
+    Assert.assertEquals(105  , message.getOptionalSint32  ());
+    Assert.assertEquals(106  , message.getOptionalSint64  ());
+    Assert.assertEquals(107  , message.getOptionalFixed32 ());
+    Assert.assertEquals(108  , message.getOptionalFixed64 ());
+    Assert.assertEquals(109  , message.getOptionalSfixed32());
+    Assert.assertEquals(110  , message.getOptionalSfixed64());
+    Assert.assertEquals(111  , message.getOptionalFloat   (), 0.0);
+    Assert.assertEquals(112  , message.getOptionalDouble  (), 0.0);
+    Assert.assertEquals(true , message.getOptionalBool    ());
+    Assert.assertEquals("115", message.getOptionalString  ());
+    Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
+
+    Assert.assertEquals(117, message.getOptionalGroup              ().getA());
+    Assert.assertEquals(118, message.getOptionalNestedMessage      ().getBb());
+    Assert.assertEquals(119, message.getOptionalForeignMessage     ().getC());
+    Assert.assertEquals(120, message.getOptionalImportMessage      ().getD());
+    Assert.assertEquals(126, message.getOptionalPublicImportMessage().getE());
+    Assert.assertEquals(127, message.getOptionalLazyMessage        ().getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
+
+    Assert.assertEquals("124", message.getOptionalStringPiece());
+    Assert.assertEquals("125", message.getOptionalCord());
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(2, message.getRepeatedStringCount  ());
+    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(2, message.getRepeatedCordCount());
+
+    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
+    Assert.assertEquals(202  , message.getRepeatedInt64   (0));
+    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
+    Assert.assertEquals(204  , message.getRepeatedUint64  (0));
+    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
+    Assert.assertEquals(206  , message.getRepeatedSint64  (0));
+    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
+    Assert.assertEquals(208  , message.getRepeatedFixed64 (0));
+    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
+    Assert.assertEquals(210  , message.getRepeatedSfixed64(0));
+    Assert.assertEquals(211  , message.getRepeatedFloat   (0), 0.0);
+    Assert.assertEquals(212  , message.getRepeatedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getRepeatedBool    (0));
+    Assert.assertEquals("215", message.getRepeatedString  (0));
+    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
+    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+    Assert.assertEquals("225", message.getRepeatedCord(0));
+
+    Assert.assertEquals(301  , message.getRepeatedInt32   (1));
+    Assert.assertEquals(302  , message.getRepeatedInt64   (1));
+    Assert.assertEquals(303  , message.getRepeatedUint32  (1));
+    Assert.assertEquals(304  , message.getRepeatedUint64  (1));
+    Assert.assertEquals(305  , message.getRepeatedSint32  (1));
+    Assert.assertEquals(306  , message.getRepeatedSint64  (1));
+    Assert.assertEquals(307  , message.getRepeatedFixed32 (1));
+    Assert.assertEquals(308  , message.getRepeatedFixed64 (1));
+    Assert.assertEquals(309  , message.getRepeatedSfixed32(1));
+    Assert.assertEquals(310  , message.getRepeatedSfixed64(1));
+    Assert.assertEquals(311  , message.getRepeatedFloat   (1), 0.0);
+    Assert.assertEquals(312  , message.getRepeatedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getRepeatedBool    (1));
+    Assert.assertEquals("315", message.getRepeatedString  (1));
+    Assert.assertEquals(toBytes("316"), message.getRepeatedBytes(1));
+
+    Assert.assertEquals(317, message.getRepeatedGroup         (1).getA());
+    Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
+    Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
+    Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
+    Assert.assertEquals(327, message.getRepeatedLazyMessage   (1).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
+    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnum(1));
+
+    Assert.assertEquals("324", message.getRepeatedStringPiece(1));
+    Assert.assertEquals("325", message.getRepeatedCord(1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasDefaultInt32   ());
+    Assert.assertTrue(message.hasDefaultInt64   ());
+    Assert.assertTrue(message.hasDefaultUint32  ());
+    Assert.assertTrue(message.hasDefaultUint64  ());
+    Assert.assertTrue(message.hasDefaultSint32  ());
+    Assert.assertTrue(message.hasDefaultSint64  ());
+    Assert.assertTrue(message.hasDefaultFixed32 ());
+    Assert.assertTrue(message.hasDefaultFixed64 ());
+    Assert.assertTrue(message.hasDefaultSfixed32());
+    Assert.assertTrue(message.hasDefaultSfixed64());
+    Assert.assertTrue(message.hasDefaultFloat   ());
+    Assert.assertTrue(message.hasDefaultDouble  ());
+    Assert.assertTrue(message.hasDefaultBool    ());
+    Assert.assertTrue(message.hasDefaultString  ());
+    Assert.assertTrue(message.hasDefaultBytes   ());
+
+    Assert.assertTrue(message.hasDefaultNestedEnum ());
+    Assert.assertTrue(message.hasDefaultForeignEnum());
+    Assert.assertTrue(message.hasDefaultImportEnum ());
+
+    Assert.assertTrue(message.hasDefaultStringPiece());
+    Assert.assertTrue(message.hasDefaultCord());
+
+    Assert.assertEquals(401  , message.getDefaultInt32   ());
+    Assert.assertEquals(402  , message.getDefaultInt64   ());
+    Assert.assertEquals(403  , message.getDefaultUint32  ());
+    Assert.assertEquals(404  , message.getDefaultUint64  ());
+    Assert.assertEquals(405  , message.getDefaultSint32  ());
+    Assert.assertEquals(406  , message.getDefaultSint64  ());
+    Assert.assertEquals(407  , message.getDefaultFixed32 ());
+    Assert.assertEquals(408  , message.getDefaultFixed64 ());
+    Assert.assertEquals(409  , message.getDefaultSfixed32());
+    Assert.assertEquals(410  , message.getDefaultSfixed64());
+    Assert.assertEquals(411  , message.getDefaultFloat   (), 0.0);
+    Assert.assertEquals(412  , message.getDefaultDouble  (), 0.0);
+    Assert.assertEquals(false, message.getDefaultBool    ());
+    Assert.assertEquals("415", message.getDefaultString  ());
+    Assert.assertEquals(toBytes("416"), message.getDefaultBytes());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
+
+    Assert.assertEquals("424", message.getDefaultStringPiece());
+    Assert.assertEquals("425", message.getDefaultCord());
+  }
+
+  // -------------------------------------------------------------------
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are cleared, and that getting the fields returns their
+   * default values.
+   */
+  public static void assertClear(TestAllTypesOrBuilder message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasOptionalInt32   ());
+    Assert.assertFalse(message.hasOptionalInt64   ());
+    Assert.assertFalse(message.hasOptionalUint32  ());
+    Assert.assertFalse(message.hasOptionalUint64  ());
+    Assert.assertFalse(message.hasOptionalSint32  ());
+    Assert.assertFalse(message.hasOptionalSint64  ());
+    Assert.assertFalse(message.hasOptionalFixed32 ());
+    Assert.assertFalse(message.hasOptionalFixed64 ());
+    Assert.assertFalse(message.hasOptionalSfixed32());
+    Assert.assertFalse(message.hasOptionalSfixed64());
+    Assert.assertFalse(message.hasOptionalFloat   ());
+    Assert.assertFalse(message.hasOptionalDouble  ());
+    Assert.assertFalse(message.hasOptionalBool    ());
+    Assert.assertFalse(message.hasOptionalString  ());
+    Assert.assertFalse(message.hasOptionalBytes   ());
+
+    Assert.assertFalse(message.hasOptionalGroup         ());
+    Assert.assertFalse(message.hasOptionalNestedMessage ());
+    Assert.assertFalse(message.hasOptionalForeignMessage());
+    Assert.assertFalse(message.hasOptionalImportMessage ());
+
+    Assert.assertFalse(message.hasOptionalNestedEnum ());
+    Assert.assertFalse(message.hasOptionalForeignEnum());
+    Assert.assertFalse(message.hasOptionalImportEnum ());
+
+    Assert.assertFalse(message.hasOptionalStringPiece());
+    Assert.assertFalse(message.hasOptionalCord());
+
+    // Optional fields without defaults are set to zero or something like it.
+    Assert.assertEquals(0    , message.getOptionalInt32   ());
+    Assert.assertEquals(0    , message.getOptionalInt64   ());
+    Assert.assertEquals(0    , message.getOptionalUint32  ());
+    Assert.assertEquals(0    , message.getOptionalUint64  ());
+    Assert.assertEquals(0    , message.getOptionalSint32  ());
+    Assert.assertEquals(0    , message.getOptionalSint64  ());
+    Assert.assertEquals(0    , message.getOptionalFixed32 ());
+    Assert.assertEquals(0    , message.getOptionalFixed64 ());
+    Assert.assertEquals(0    , message.getOptionalSfixed32());
+    Assert.assertEquals(0    , message.getOptionalSfixed64());
+    Assert.assertEquals(0    , message.getOptionalFloat   (), 0.0);
+    Assert.assertEquals(0    , message.getOptionalDouble  (), 0.0);
+    Assert.assertEquals(false, message.getOptionalBool    ());
+    Assert.assertEquals(""   , message.getOptionalString  ());
+    Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getOptionalGroup              ().hasA());
+    Assert.assertFalse(message.getOptionalNestedMessage      ().hasBb());
+    Assert.assertFalse(message.getOptionalForeignMessage     ().hasC());
+    Assert.assertFalse(message.getOptionalImportMessage      ().hasD());
+    Assert.assertFalse(message.getOptionalPublicImportMessage().hasE());
+    Assert.assertFalse(message.getOptionalLazyMessage        ().hasBb());
+
+    Assert.assertEquals(0, message.getOptionalGroup              ().getA());
+    Assert.assertEquals(0, message.getOptionalNestedMessage      ().getBb());
+    Assert.assertEquals(0, message.getOptionalForeignMessage     ().getC());
+    Assert.assertEquals(0, message.getOptionalImportMessage      ().getD());
+    Assert.assertEquals(0, message.getOptionalPublicImportMessage().getE());
+    Assert.assertEquals(0, message.getOptionalLazyMessage        ().getBb());
+
+    // Enums without defaults are set to the first value in the enum.
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getOptionalForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getOptionalImportEnum());
+
+    Assert.assertEquals("", message.getOptionalStringPiece());
+    Assert.assertEquals("", message.getOptionalCord());
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(0, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(0, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(0, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(0, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(0, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(0, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(0, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(0, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(0, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(0, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(0, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(0, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(0, message.getRepeatedStringCount  ());
+    Assert.assertEquals(0, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(0, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(0, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(0, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(0, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(0, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(0, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(0, message.getRepeatedCordCount());
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasDefaultInt32   ());
+    Assert.assertFalse(message.hasDefaultInt64   ());
+    Assert.assertFalse(message.hasDefaultUint32  ());
+    Assert.assertFalse(message.hasDefaultUint64  ());
+    Assert.assertFalse(message.hasDefaultSint32  ());
+    Assert.assertFalse(message.hasDefaultSint64  ());
+    Assert.assertFalse(message.hasDefaultFixed32 ());
+    Assert.assertFalse(message.hasDefaultFixed64 ());
+    Assert.assertFalse(message.hasDefaultSfixed32());
+    Assert.assertFalse(message.hasDefaultSfixed64());
+    Assert.assertFalse(message.hasDefaultFloat   ());
+    Assert.assertFalse(message.hasDefaultDouble  ());
+    Assert.assertFalse(message.hasDefaultBool    ());
+    Assert.assertFalse(message.hasDefaultString  ());
+    Assert.assertFalse(message.hasDefaultBytes   ());
+
+    Assert.assertFalse(message.hasDefaultNestedEnum ());
+    Assert.assertFalse(message.hasDefaultForeignEnum());
+    Assert.assertFalse(message.hasDefaultImportEnum ());
+
+    Assert.assertFalse(message.hasDefaultStringPiece());
+    Assert.assertFalse(message.hasDefaultCord());
+
+    // Fields with defaults have their default values (duh).
+    Assert.assertEquals( 41    , message.getDefaultInt32   ());
+    Assert.assertEquals( 42    , message.getDefaultInt64   ());
+    Assert.assertEquals( 43    , message.getDefaultUint32  ());
+    Assert.assertEquals( 44    , message.getDefaultUint64  ());
+    Assert.assertEquals(-45    , message.getDefaultSint32  ());
+    Assert.assertEquals( 46    , message.getDefaultSint64  ());
+    Assert.assertEquals( 47    , message.getDefaultFixed32 ());
+    Assert.assertEquals( 48    , message.getDefaultFixed64 ());
+    Assert.assertEquals( 49    , message.getDefaultSfixed32());
+    Assert.assertEquals(-50    , message.getDefaultSfixed64());
+    Assert.assertEquals( 51.5  , message.getDefaultFloat   (), 0.0);
+    Assert.assertEquals( 52e3  , message.getDefaultDouble  (), 0.0);
+    Assert.assertEquals(true   , message.getDefaultBool    ());
+    Assert.assertEquals("hello", message.getDefaultString  ());
+    Assert.assertEquals(toBytes("world"), message.getDefaultBytes());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
+
+    Assert.assertEquals("abc", message.getDefaultStringPiece());
+    Assert.assertEquals("123", message.getDefaultCord());
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setAllFields}
+   * followed by {@code modifyRepeatedFields}.
+   */
+  public static void assertRepeatedFieldsModified(
+      TestAllTypesOrBuilder message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(2, message.getRepeatedStringCount  ());
+    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(2, message.getRepeatedCordCount());
+
+    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
+    Assert.assertEquals(202L , message.getRepeatedInt64   (0));
+    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
+    Assert.assertEquals(204L , message.getRepeatedUint64  (0));
+    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
+    Assert.assertEquals(206L , message.getRepeatedSint64  (0));
+    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
+    Assert.assertEquals(208L , message.getRepeatedFixed64 (0));
+    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
+    Assert.assertEquals(210L , message.getRepeatedSfixed64(0));
+    Assert.assertEquals(211F , message.getRepeatedFloat   (0));
+    Assert.assertEquals(212D , message.getRepeatedDouble  (0));
+    Assert.assertEquals(true , message.getRepeatedBool    (0));
+    Assert.assertEquals("215", message.getRepeatedString  (0));
+    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
+    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+    Assert.assertEquals("225", message.getRepeatedCord(0));
+
+    // Actually verify the second (modified) elements now.
+    Assert.assertEquals(501  , message.getRepeatedInt32   (1));
+    Assert.assertEquals(502L , message.getRepeatedInt64   (1));
+    Assert.assertEquals(503  , message.getRepeatedUint32  (1));
+    Assert.assertEquals(504L , message.getRepeatedUint64  (1));
+    Assert.assertEquals(505  , message.getRepeatedSint32  (1));
+    Assert.assertEquals(506L , message.getRepeatedSint64  (1));
+    Assert.assertEquals(507  , message.getRepeatedFixed32 (1));
+    Assert.assertEquals(508L , message.getRepeatedFixed64 (1));
+    Assert.assertEquals(509  , message.getRepeatedSfixed32(1));
+    Assert.assertEquals(510L , message.getRepeatedSfixed64(1));
+    Assert.assertEquals(511F , message.getRepeatedFloat   (1));
+    Assert.assertEquals(512D , message.getRepeatedDouble  (1));
+    Assert.assertEquals(true , message.getRepeatedBool    (1));
+    Assert.assertEquals("515", message.getRepeatedString  (1));
+    Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
+
+    Assert.assertEquals(517, message.getRepeatedGroup         (1).getA());
+    Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
+    Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
+    Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
+    Assert.assertEquals(527, message.getRepeatedLazyMessage   (1).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnum(1));
+
+    Assert.assertEquals("524", message.getRepeatedStringPiece(1));
+    Assert.assertEquals("525", message.getRepeatedCord(1));
+  }
+
+  /**
+   * Set every field of {@code message} to a unique value.
+   */
+  public static void setPackedFields(TestPackedTypes.Builder message) {
+    message.addPackedInt32   (601);
+    message.addPackedInt64   (602);
+    message.addPackedUint32  (603);
+    message.addPackedUint64  (604);
+    message.addPackedSint32  (605);
+    message.addPackedSint64  (606);
+    message.addPackedFixed32 (607);
+    message.addPackedFixed64 (608);
+    message.addPackedSfixed32(609);
+    message.addPackedSfixed64(610);
+    message.addPackedFloat   (611);
+    message.addPackedDouble  (612);
+    message.addPackedBool    (true);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addPackedInt32   (701);
+    message.addPackedInt64   (702);
+    message.addPackedUint32  (703);
+    message.addPackedUint64  (704);
+    message.addPackedSint32  (705);
+    message.addPackedSint64  (706);
+    message.addPackedFixed32 (707);
+    message.addPackedFixed64 (708);
+    message.addPackedSfixed32(709);
+    message.addPackedSfixed64(710);
+    message.addPackedFloat   (711);
+    message.addPackedDouble  (712);
+    message.addPackedBool    (false);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAZ);
+  }
+
+  /**
+   * Set every field of {@code message} to a unique value. Must correspond with
+   * the values applied by {@code setPackedFields}.
+   */
+  public static void setUnpackedFields(TestUnpackedTypes.Builder message) {
+    message.addUnpackedInt32   (601);
+    message.addUnpackedInt64   (602);
+    message.addUnpackedUint32  (603);
+    message.addUnpackedUint64  (604);
+    message.addUnpackedSint32  (605);
+    message.addUnpackedSint64  (606);
+    message.addUnpackedFixed32 (607);
+    message.addUnpackedFixed64 (608);
+    message.addUnpackedSfixed32(609);
+    message.addUnpackedSfixed64(610);
+    message.addUnpackedFloat   (611);
+    message.addUnpackedDouble  (612);
+    message.addUnpackedBool    (true);
+    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addUnpackedInt32   (701);
+    message.addUnpackedInt64   (702);
+    message.addUnpackedUint32  (703);
+    message.addUnpackedUint64  (704);
+    message.addUnpackedSint32  (705);
+    message.addUnpackedSint64  (706);
+    message.addUnpackedFixed32 (707);
+    message.addUnpackedFixed64 (708);
+    message.addUnpackedSfixed32(709);
+    message.addUnpackedSfixed64(710);
+    message.addUnpackedFloat   (711);
+    message.addUnpackedDouble  (712);
+    message.addUnpackedBool    (false);
+    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAZ);
+  }
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setPackedFields}.
+   */
+  public static void assertPackedFieldsSet(TestPackedTypes message) {
+    Assert.assertEquals(2, message.getPackedInt32Count   ());
+    Assert.assertEquals(2, message.getPackedInt64Count   ());
+    Assert.assertEquals(2, message.getPackedUint32Count  ());
+    Assert.assertEquals(2, message.getPackedUint64Count  ());
+    Assert.assertEquals(2, message.getPackedSint32Count  ());
+    Assert.assertEquals(2, message.getPackedSint64Count  ());
+    Assert.assertEquals(2, message.getPackedFixed32Count ());
+    Assert.assertEquals(2, message.getPackedFixed64Count ());
+    Assert.assertEquals(2, message.getPackedSfixed32Count());
+    Assert.assertEquals(2, message.getPackedSfixed64Count());
+    Assert.assertEquals(2, message.getPackedFloatCount   ());
+    Assert.assertEquals(2, message.getPackedDoubleCount  ());
+    Assert.assertEquals(2, message.getPackedBoolCount    ());
+    Assert.assertEquals(2, message.getPackedEnumCount   ());
+    Assert.assertEquals(601  , message.getPackedInt32   (0));
+    Assert.assertEquals(602  , message.getPackedInt64   (0));
+    Assert.assertEquals(603  , message.getPackedUint32  (0));
+    Assert.assertEquals(604  , message.getPackedUint64  (0));
+    Assert.assertEquals(605  , message.getPackedSint32  (0));
+    Assert.assertEquals(606  , message.getPackedSint64  (0));
+    Assert.assertEquals(607  , message.getPackedFixed32 (0));
+    Assert.assertEquals(608  , message.getPackedFixed64 (0));
+    Assert.assertEquals(609  , message.getPackedSfixed32(0));
+    Assert.assertEquals(610  , message.getPackedSfixed64(0));
+    Assert.assertEquals(611  , message.getPackedFloat   (0), 0.0);
+    Assert.assertEquals(612  , message.getPackedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getPackedBool    (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
+    Assert.assertEquals(701  , message.getPackedInt32   (1));
+    Assert.assertEquals(702  , message.getPackedInt64   (1));
+    Assert.assertEquals(703  , message.getPackedUint32  (1));
+    Assert.assertEquals(704  , message.getPackedUint64  (1));
+    Assert.assertEquals(705  , message.getPackedSint32  (1));
+    Assert.assertEquals(706  , message.getPackedSint64  (1));
+    Assert.assertEquals(707  , message.getPackedFixed32 (1));
+    Assert.assertEquals(708  , message.getPackedFixed64 (1));
+    Assert.assertEquals(709  , message.getPackedSfixed32(1));
+    Assert.assertEquals(710  , message.getPackedSfixed64(1));
+    Assert.assertEquals(711  , message.getPackedFloat   (1), 0.0);
+    Assert.assertEquals(712  , message.getPackedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getPackedBool    (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
+  }
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setUnpackedFields}.
+   */
+  public static void assertUnpackedFieldsSet(TestUnpackedTypes message) {
+    Assert.assertEquals(2, message.getUnpackedInt32Count   ());
+    Assert.assertEquals(2, message.getUnpackedInt64Count   ());
+    Assert.assertEquals(2, message.getUnpackedUint32Count  ());
+    Assert.assertEquals(2, message.getUnpackedUint64Count  ());
+    Assert.assertEquals(2, message.getUnpackedSint32Count  ());
+    Assert.assertEquals(2, message.getUnpackedSint64Count  ());
+    Assert.assertEquals(2, message.getUnpackedFixed32Count ());
+    Assert.assertEquals(2, message.getUnpackedFixed64Count ());
+    Assert.assertEquals(2, message.getUnpackedSfixed32Count());
+    Assert.assertEquals(2, message.getUnpackedSfixed64Count());
+    Assert.assertEquals(2, message.getUnpackedFloatCount   ());
+    Assert.assertEquals(2, message.getUnpackedDoubleCount  ());
+    Assert.assertEquals(2, message.getUnpackedBoolCount    ());
+    Assert.assertEquals(2, message.getUnpackedEnumCount   ());
+    Assert.assertEquals(601  , message.getUnpackedInt32   (0));
+    Assert.assertEquals(602  , message.getUnpackedInt64   (0));
+    Assert.assertEquals(603  , message.getUnpackedUint32  (0));
+    Assert.assertEquals(604  , message.getUnpackedUint64  (0));
+    Assert.assertEquals(605  , message.getUnpackedSint32  (0));
+    Assert.assertEquals(606  , message.getUnpackedSint64  (0));
+    Assert.assertEquals(607  , message.getUnpackedFixed32 (0));
+    Assert.assertEquals(608  , message.getUnpackedFixed64 (0));
+    Assert.assertEquals(609  , message.getUnpackedSfixed32(0));
+    Assert.assertEquals(610  , message.getUnpackedSfixed64(0));
+    Assert.assertEquals(611  , message.getUnpackedFloat   (0), 0.0);
+    Assert.assertEquals(612  , message.getUnpackedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getUnpackedBool    (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getUnpackedEnum(0));
+    Assert.assertEquals(701  , message.getUnpackedInt32   (1));
+    Assert.assertEquals(702  , message.getUnpackedInt64   (1));
+    Assert.assertEquals(703  , message.getUnpackedUint32  (1));
+    Assert.assertEquals(704  , message.getUnpackedUint64  (1));
+    Assert.assertEquals(705  , message.getUnpackedSint32  (1));
+    Assert.assertEquals(706  , message.getUnpackedSint64  (1));
+    Assert.assertEquals(707  , message.getUnpackedFixed32 (1));
+    Assert.assertEquals(708  , message.getUnpackedFixed64 (1));
+    Assert.assertEquals(709  , message.getUnpackedSfixed32(1));
+    Assert.assertEquals(710  , message.getUnpackedSfixed64(1));
+    Assert.assertEquals(711  , message.getUnpackedFloat   (1), 0.0);
+    Assert.assertEquals(712  , message.getUnpackedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getUnpackedBool    (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getUnpackedEnum(1));
+  }
+
+  // ===================================================================
+  // Like above, but for extensions
+
+  // Java gets confused with things like assertEquals(int, Integer):  it can't
+  // decide whether to call assertEquals(int, int) or assertEquals(Object,
+  // Object).  So we define these methods to help it.
+  private static void assertEqualsExactType(int a, int b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(long a, long b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(float a, float b) {
+    Assert.assertEquals(a, b, 0.0);
+  }
+  private static void assertEqualsExactType(double a, double b) {
+    Assert.assertEquals(a, b, 0.0);
+  }
+  private static void assertEqualsExactType(boolean a, boolean b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(String a, String b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ByteString a, ByteString b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
+                                            TestAllTypes.NestedEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  /**
+   * Get an unmodifiable {@link ExtensionRegistry} containing all the
+   * extensions of {@code TestAllExtensions}.
+   */
+  public static ExtensionRegistry getExtensionRegistry() {
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    registerAllExtensions(registry);
+    return registry.getUnmodifiable();
+  }
+
+
+  /**
+   * Register all of {@code TestAllExtensions}'s extensions with the
+   * given {@link ExtensionRegistry}.
+   */
+  public static void registerAllExtensions(ExtensionRegistry registry) {
+    UnittestProto.registerAllExtensions(registry);
+  }
+
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllExtensionsSet()}.
+   */
+  public static void setAllExtensions(TestAllExtensions.Builder message) {
+    message.setExtension(optionalInt32Extension   , 101);
+    message.setExtension(optionalInt64Extension   , 102L);
+    message.setExtension(optionalUint32Extension  , 103);
+    message.setExtension(optionalUint64Extension  , 104L);
+    message.setExtension(optionalSint32Extension  , 105);
+    message.setExtension(optionalSint64Extension  , 106L);
+    message.setExtension(optionalFixed32Extension , 107);
+    message.setExtension(optionalFixed64Extension , 108L);
+    message.setExtension(optionalSfixed32Extension, 109);
+    message.setExtension(optionalSfixed64Extension, 110L);
+    message.setExtension(optionalFloatExtension   , 111F);
+    message.setExtension(optionalDoubleExtension  , 112D);
+    message.setExtension(optionalBoolExtension    , true);
+    message.setExtension(optionalStringExtension  , "115");
+    message.setExtension(optionalBytesExtension   , toBytes("116"));
+
+    message.setExtension(optionalGroupExtension,
+      OptionalGroup_extension.newBuilder().setA(117).build());
+    message.setExtension(optionalNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+    message.setExtension(optionalForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(119).build());
+    message.setExtension(optionalImportMessageExtension,
+      ImportMessage.newBuilder().setD(120).build());
+    message.setExtension(optionalPublicImportMessageExtension,
+      PublicImportMessage.newBuilder().setE(126).build());
+    message.setExtension(optionalLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+    message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+    message.setExtension(optionalImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+    message.setExtension(optionalStringPieceExtension, "124");
+    message.setExtension(optionalCordExtension, "125");
+
+    // -----------------------------------------------------------------
+
+    message.addExtension(repeatedInt32Extension   , 201);
+    message.addExtension(repeatedInt64Extension   , 202L);
+    message.addExtension(repeatedUint32Extension  , 203);
+    message.addExtension(repeatedUint64Extension  , 204L);
+    message.addExtension(repeatedSint32Extension  , 205);
+    message.addExtension(repeatedSint64Extension  , 206L);
+    message.addExtension(repeatedFixed32Extension , 207);
+    message.addExtension(repeatedFixed64Extension , 208L);
+    message.addExtension(repeatedSfixed32Extension, 209);
+    message.addExtension(repeatedSfixed64Extension, 210L);
+    message.addExtension(repeatedFloatExtension   , 211F);
+    message.addExtension(repeatedDoubleExtension  , 212D);
+    message.addExtension(repeatedBoolExtension    , true);
+    message.addExtension(repeatedStringExtension  , "215");
+    message.addExtension(repeatedBytesExtension   , toBytes("216"));
+
+    message.addExtension(repeatedGroupExtension,
+      RepeatedGroup_extension.newBuilder().setA(217).build());
+    message.addExtension(repeatedNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    message.addExtension(repeatedForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(219).build());
+    message.addExtension(repeatedImportMessageExtension,
+      ImportMessage.newBuilder().setD(220).build());
+    message.addExtension(repeatedLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR);
+    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR);
+    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAR);
+
+    message.addExtension(repeatedStringPieceExtension, "224");
+    message.addExtension(repeatedCordExtension, "225");
+
+    // Add a second one of each field.
+    message.addExtension(repeatedInt32Extension   , 301);
+    message.addExtension(repeatedInt64Extension   , 302L);
+    message.addExtension(repeatedUint32Extension  , 303);
+    message.addExtension(repeatedUint64Extension  , 304L);
+    message.addExtension(repeatedSint32Extension  , 305);
+    message.addExtension(repeatedSint64Extension  , 306L);
+    message.addExtension(repeatedFixed32Extension , 307);
+    message.addExtension(repeatedFixed64Extension , 308L);
+    message.addExtension(repeatedSfixed32Extension, 309);
+    message.addExtension(repeatedSfixed64Extension, 310L);
+    message.addExtension(repeatedFloatExtension   , 311F);
+    message.addExtension(repeatedDoubleExtension  , 312D);
+    message.addExtension(repeatedBoolExtension    , false);
+    message.addExtension(repeatedStringExtension  , "315");
+    message.addExtension(repeatedBytesExtension   , toBytes("316"));
+
+    message.addExtension(repeatedGroupExtension,
+      RepeatedGroup_extension.newBuilder().setA(317).build());
+    message.addExtension(repeatedNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+    message.addExtension(repeatedForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(319).build());
+    message.addExtension(repeatedImportMessageExtension,
+      ImportMessage.newBuilder().setD(320).build());
+    message.addExtension(repeatedLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+    message.addExtension(repeatedStringPieceExtension, "324");
+    message.addExtension(repeatedCordExtension, "325");
+
+    // -----------------------------------------------------------------
+
+    message.setExtension(defaultInt32Extension   , 401);
+    message.setExtension(defaultInt64Extension   , 402L);
+    message.setExtension(defaultUint32Extension  , 403);
+    message.setExtension(defaultUint64Extension  , 404L);
+    message.setExtension(defaultSint32Extension  , 405);
+    message.setExtension(defaultSint64Extension  , 406L);
+    message.setExtension(defaultFixed32Extension , 407);
+    message.setExtension(defaultFixed64Extension , 408L);
+    message.setExtension(defaultSfixed32Extension, 409);
+    message.setExtension(defaultSfixed64Extension, 410L);
+    message.setExtension(defaultFloatExtension   , 411F);
+    message.setExtension(defaultDoubleExtension  , 412D);
+    message.setExtension(defaultBoolExtension    , false);
+    message.setExtension(defaultStringExtension  , "415");
+    message.setExtension(defaultBytesExtension   , toBytes("416"));
+
+    message.setExtension(defaultNestedEnumExtension, TestAllTypes.NestedEnum.FOO);
+    message.setExtension(defaultForeignEnumExtension, ForeignEnum.FOREIGN_FOO);
+    message.setExtension(defaultImportEnumExtension, ImportEnum.IMPORT_FOO);
+
+    message.setExtension(defaultStringPieceExtension, "424");
+    message.setExtension(defaultCordExtension, "425");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated extensions of {@code message} to contain the values
+   * expected by {@code assertRepeatedExtensionsModified()}.
+   */
+  public static void modifyRepeatedExtensions(
+      TestAllExtensions.Builder message) {
+    message.setExtension(repeatedInt32Extension   , 1, 501);
+    message.setExtension(repeatedInt64Extension   , 1, 502L);
+    message.setExtension(repeatedUint32Extension  , 1, 503);
+    message.setExtension(repeatedUint64Extension  , 1, 504L);
+    message.setExtension(repeatedSint32Extension  , 1, 505);
+    message.setExtension(repeatedSint64Extension  , 1, 506L);
+    message.setExtension(repeatedFixed32Extension , 1, 507);
+    message.setExtension(repeatedFixed64Extension , 1, 508L);
+    message.setExtension(repeatedSfixed32Extension, 1, 509);
+    message.setExtension(repeatedSfixed64Extension, 1, 510L);
+    message.setExtension(repeatedFloatExtension   , 1, 511F);
+    message.setExtension(repeatedDoubleExtension  , 1, 512D);
+    message.setExtension(repeatedBoolExtension    , 1, true);
+    message.setExtension(repeatedStringExtension  , 1, "515");
+    message.setExtension(repeatedBytesExtension   , 1, toBytes("516"));
+
+    message.setExtension(repeatedGroupExtension, 1,
+      RepeatedGroup_extension.newBuilder().setA(517).build());
+    message.setExtension(repeatedNestedMessageExtension, 1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+    message.setExtension(repeatedForeignMessageExtension, 1,
+      ForeignMessage.newBuilder().setC(519).build());
+    message.setExtension(repeatedImportMessageExtension, 1,
+      ImportMessage.newBuilder().setD(520).build());
+    message.setExtension(repeatedLazyMessageExtension, 1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO);
+    message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO);
+    message.setExtension(repeatedImportEnumExtension , 1, ImportEnum.IMPORT_FOO);
+
+    message.setExtension(repeatedStringPieceExtension, 1, "524");
+    message.setExtension(repeatedCordExtension, 1, "525");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}.
+   */
+  public static void assertAllExtensionsSet(
+      TestAllExtensionsOrBuilder message) {
+    Assert.assertTrue(message.hasExtension(optionalInt32Extension   ));
+    Assert.assertTrue(message.hasExtension(optionalInt64Extension   ));
+    Assert.assertTrue(message.hasExtension(optionalUint32Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalUint64Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalSint32Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalSint64Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalFixed32Extension ));
+    Assert.assertTrue(message.hasExtension(optionalFixed64Extension ));
+    Assert.assertTrue(message.hasExtension(optionalSfixed32Extension));
+    Assert.assertTrue(message.hasExtension(optionalSfixed64Extension));
+    Assert.assertTrue(message.hasExtension(optionalFloatExtension   ));
+    Assert.assertTrue(message.hasExtension(optionalDoubleExtension  ));
+    Assert.assertTrue(message.hasExtension(optionalBoolExtension    ));
+    Assert.assertTrue(message.hasExtension(optionalStringExtension  ));
+    Assert.assertTrue(message.hasExtension(optionalBytesExtension   ));
+
+    Assert.assertTrue(message.hasExtension(optionalGroupExtension         ));
+    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtension ));
+    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtension));
+    Assert.assertTrue(message.hasExtension(optionalImportMessageExtension ));
+
+    Assert.assertTrue(message.getExtension(optionalGroupExtension         ).hasA());
+    Assert.assertTrue(message.getExtension(optionalNestedMessageExtension ).hasBb());
+    Assert.assertTrue(message.getExtension(optionalForeignMessageExtension).hasC());
+    Assert.assertTrue(message.getExtension(optionalImportMessageExtension ).hasD());
+
+    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtension ));
+    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtension));
+    Assert.assertTrue(message.hasExtension(optionalImportEnumExtension ));
+
+    Assert.assertTrue(message.hasExtension(optionalStringPieceExtension));
+    Assert.assertTrue(message.hasExtension(optionalCordExtension));
+
+    assertEqualsExactType(101  , message.getExtension(optionalInt32Extension   ));
+    assertEqualsExactType(102L , message.getExtension(optionalInt64Extension   ));
+    assertEqualsExactType(103  , message.getExtension(optionalUint32Extension  ));
+    assertEqualsExactType(104L , message.getExtension(optionalUint64Extension  ));
+    assertEqualsExactType(105  , message.getExtension(optionalSint32Extension  ));
+    assertEqualsExactType(106L , message.getExtension(optionalSint64Extension  ));
+    assertEqualsExactType(107  , message.getExtension(optionalFixed32Extension ));
+    assertEqualsExactType(108L , message.getExtension(optionalFixed64Extension ));
+    assertEqualsExactType(109  , message.getExtension(optionalSfixed32Extension));
+    assertEqualsExactType(110L , message.getExtension(optionalSfixed64Extension));
+    assertEqualsExactType(111F , message.getExtension(optionalFloatExtension   ));
+    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtension  ));
+    assertEqualsExactType(true , message.getExtension(optionalBoolExtension    ));
+    assertEqualsExactType("115", message.getExtension(optionalStringExtension  ));
+    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension));
+
+    assertEqualsExactType(117, message.getExtension(optionalGroupExtension              ).getA());
+    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension      ).getBb());
+    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension     ).getC());
+    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension      ).getD());
+    assertEqualsExactType(126, message.getExtension(optionalPublicImportMessageExtension).getE());
+    assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtension        ).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+      message.getExtension(optionalNestedEnumExtension));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+      message.getExtension(optionalForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+      message.getExtension(optionalImportEnumExtension));
+
+    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtension));
+    assertEqualsExactType("125", message.getExtension(optionalCordExtension));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtension, 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(repeatedForeignEnumExtension, 0));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(repeatedImportEnumExtension, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+    assertEqualsExactType(301  , message.getExtension(repeatedInt32Extension   , 1));
+    assertEqualsExactType(302L , message.getExtension(repeatedInt64Extension   , 1));
+    assertEqualsExactType(303  , message.getExtension(repeatedUint32Extension  , 1));
+    assertEqualsExactType(304L , message.getExtension(repeatedUint64Extension  , 1));
+    assertEqualsExactType(305  , message.getExtension(repeatedSint32Extension  , 1));
+    assertEqualsExactType(306L , message.getExtension(repeatedSint64Extension  , 1));
+    assertEqualsExactType(307  , message.getExtension(repeatedFixed32Extension , 1));
+    assertEqualsExactType(308L , message.getExtension(repeatedFixed64Extension , 1));
+    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32Extension, 1));
+    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64Extension, 1));
+    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtension   , 1));
+    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtension  , 1));
+    assertEqualsExactType(false, message.getExtension(repeatedBoolExtension    , 1));
+    assertEqualsExactType("315", message.getExtension(repeatedStringExtension  , 1));
+    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtension, 1));
+
+    assertEqualsExactType(317, message.getExtension(repeatedGroupExtension         , 1).getA());
+    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD());
+    assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+      message.getExtension(repeatedNestedEnumExtension, 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+      message.getExtension(repeatedForeignEnumExtension, 1));
+    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+      message.getExtension(repeatedImportEnumExtension, 1));
+
+    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtension, 1));
+    assertEqualsExactType("325", message.getExtension(repeatedCordExtension, 1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasExtension(defaultInt32Extension   ));
+    Assert.assertTrue(message.hasExtension(defaultInt64Extension   ));
+    Assert.assertTrue(message.hasExtension(defaultUint32Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultUint64Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultSint32Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultSint64Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultFixed32Extension ));
+    Assert.assertTrue(message.hasExtension(defaultFixed64Extension ));
+    Assert.assertTrue(message.hasExtension(defaultSfixed32Extension));
+    Assert.assertTrue(message.hasExtension(defaultSfixed64Extension));
+    Assert.assertTrue(message.hasExtension(defaultFloatExtension   ));
+    Assert.assertTrue(message.hasExtension(defaultDoubleExtension  ));
+    Assert.assertTrue(message.hasExtension(defaultBoolExtension    ));
+    Assert.assertTrue(message.hasExtension(defaultStringExtension  ));
+    Assert.assertTrue(message.hasExtension(defaultBytesExtension   ));
+
+    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtension ));
+    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtension));
+    Assert.assertTrue(message.hasExtension(defaultImportEnumExtension ));
+
+    Assert.assertTrue(message.hasExtension(defaultStringPieceExtension));
+    Assert.assertTrue(message.hasExtension(defaultCordExtension));
+
+    assertEqualsExactType(401  , message.getExtension(defaultInt32Extension   ));
+    assertEqualsExactType(402L , message.getExtension(defaultInt64Extension   ));
+    assertEqualsExactType(403  , message.getExtension(defaultUint32Extension  ));
+    assertEqualsExactType(404L , message.getExtension(defaultUint64Extension  ));
+    assertEqualsExactType(405  , message.getExtension(defaultSint32Extension  ));
+    assertEqualsExactType(406L , message.getExtension(defaultSint64Extension  ));
+    assertEqualsExactType(407  , message.getExtension(defaultFixed32Extension ));
+    assertEqualsExactType(408L , message.getExtension(defaultFixed64Extension ));
+    assertEqualsExactType(409  , message.getExtension(defaultSfixed32Extension));
+    assertEqualsExactType(410L , message.getExtension(defaultSfixed64Extension));
+    assertEqualsExactType(411F , message.getExtension(defaultFloatExtension   ));
+    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtension  ));
+    assertEqualsExactType(false, message.getExtension(defaultBoolExtension    ));
+    assertEqualsExactType("415", message.getExtension(defaultStringExtension  ));
+    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtension));
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(defaultNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(defaultForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(defaultImportEnumExtension));
+
+    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
+    assertEqualsExactType("425", message.getExtension(defaultCordExtension));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are cleared, and that getting the extensions returns their
+   * default values.
+   */
+  public static void assertExtensionsClear(TestAllExtensionsOrBuilder message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasExtension(optionalInt32Extension   ));
+    Assert.assertFalse(message.hasExtension(optionalInt64Extension   ));
+    Assert.assertFalse(message.hasExtension(optionalUint32Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalUint64Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalSint32Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalSint64Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalFixed32Extension ));
+    Assert.assertFalse(message.hasExtension(optionalFixed64Extension ));
+    Assert.assertFalse(message.hasExtension(optionalSfixed32Extension));
+    Assert.assertFalse(message.hasExtension(optionalSfixed64Extension));
+    Assert.assertFalse(message.hasExtension(optionalFloatExtension   ));
+    Assert.assertFalse(message.hasExtension(optionalDoubleExtension  ));
+    Assert.assertFalse(message.hasExtension(optionalBoolExtension    ));
+    Assert.assertFalse(message.hasExtension(optionalStringExtension  ));
+    Assert.assertFalse(message.hasExtension(optionalBytesExtension   ));
+
+    Assert.assertFalse(message.hasExtension(optionalGroupExtension         ));
+    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtension ));
+    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtension));
+    Assert.assertFalse(message.hasExtension(optionalImportMessageExtension ));
+
+    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtension ));
+    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtension));
+    Assert.assertFalse(message.hasExtension(optionalImportEnumExtension ));
+
+    Assert.assertFalse(message.hasExtension(optionalStringPieceExtension));
+    Assert.assertFalse(message.hasExtension(optionalCordExtension));
+
+    // Optional fields without defaults are set to zero or something like it.
+    assertEqualsExactType(0    , message.getExtension(optionalInt32Extension   ));
+    assertEqualsExactType(0L   , message.getExtension(optionalInt64Extension   ));
+    assertEqualsExactType(0    , message.getExtension(optionalUint32Extension  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalUint64Extension  ));
+    assertEqualsExactType(0    , message.getExtension(optionalSint32Extension  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalSint64Extension  ));
+    assertEqualsExactType(0    , message.getExtension(optionalFixed32Extension ));
+    assertEqualsExactType(0L   , message.getExtension(optionalFixed64Extension ));
+    assertEqualsExactType(0    , message.getExtension(optionalSfixed32Extension));
+    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64Extension));
+    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtension   ));
+    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtension  ));
+    assertEqualsExactType(false, message.getExtension(optionalBoolExtension    ));
+    assertEqualsExactType(""   , message.getExtension(optionalStringExtension  ));
+    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtension));
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getExtension(optionalGroupExtension         ).hasA());
+    Assert.assertFalse(message.getExtension(optionalNestedMessageExtension ).hasBb());
+    Assert.assertFalse(message.getExtension(optionalForeignMessageExtension).hasC());
+    Assert.assertFalse(message.getExtension(optionalImportMessageExtension ).hasD());
+
+    assertEqualsExactType(0, message.getExtension(optionalGroupExtension         ).getA());
+    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtension ).getBb());
+    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtension).getC());
+    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtension ).getD());
+
+    // Enums without defaults are set to the first value in the enum.
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(optionalNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(optionalForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(optionalImportEnumExtension));
+
+    assertEqualsExactType("", message.getExtension(optionalStringPieceExtension));
+    assertEqualsExactType("", message.getExtension(optionalCordExtension));
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtension));
+
+    // Repeated fields are empty via getExtension().size().
+    Assert.assertEquals(0, message.getExtension(repeatedInt32Extension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedInt64Extension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedUint32Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedUint64Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSint32Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSint64Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFixed32Extension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFixed64Extension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSfixed32Extension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSfixed64Extension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFloatExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedDoubleExtension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedBoolExtension    ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedStringExtension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedBytesExtension   ).size());
+
+    Assert.assertEquals(0, message.getExtension(repeatedGroupExtension         ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedNestedMessageExtension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedForeignMessageExtension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedImportMessageExtension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedLazyMessageExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedNestedEnumExtension    ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedForeignEnumExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedImportEnumExtension    ).size());
+
+    Assert.assertEquals(0, message.getExtension(repeatedStringPieceExtension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedCordExtension).size());
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasExtension(defaultInt32Extension   ));
+    Assert.assertFalse(message.hasExtension(defaultInt64Extension   ));
+    Assert.assertFalse(message.hasExtension(defaultUint32Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultUint64Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultSint32Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultSint64Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultFixed32Extension ));
+    Assert.assertFalse(message.hasExtension(defaultFixed64Extension ));
+    Assert.assertFalse(message.hasExtension(defaultSfixed32Extension));
+    Assert.assertFalse(message.hasExtension(defaultSfixed64Extension));
+    Assert.assertFalse(message.hasExtension(defaultFloatExtension   ));
+    Assert.assertFalse(message.hasExtension(defaultDoubleExtension  ));
+    Assert.assertFalse(message.hasExtension(defaultBoolExtension    ));
+    Assert.assertFalse(message.hasExtension(defaultStringExtension  ));
+    Assert.assertFalse(message.hasExtension(defaultBytesExtension   ));
+
+    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtension ));
+    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtension));
+    Assert.assertFalse(message.hasExtension(defaultImportEnumExtension ));
+
+    Assert.assertFalse(message.hasExtension(defaultStringPieceExtension));
+    Assert.assertFalse(message.hasExtension(defaultCordExtension));
+
+    // Fields with defaults have their default values (duh).
+    assertEqualsExactType( 41    , message.getExtension(defaultInt32Extension   ));
+    assertEqualsExactType( 42L   , message.getExtension(defaultInt64Extension   ));
+    assertEqualsExactType( 43    , message.getExtension(defaultUint32Extension  ));
+    assertEqualsExactType( 44L   , message.getExtension(defaultUint64Extension  ));
+    assertEqualsExactType(-45    , message.getExtension(defaultSint32Extension  ));
+    assertEqualsExactType( 46L   , message.getExtension(defaultSint64Extension  ));
+    assertEqualsExactType( 47    , message.getExtension(defaultFixed32Extension ));
+    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64Extension ));
+    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32Extension));
+    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64Extension));
+    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtension   ));
+    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtension  ));
+    assertEqualsExactType(true   , message.getExtension(defaultBoolExtension    ));
+    assertEqualsExactType("hello", message.getExtension(defaultStringExtension  ));
+    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtension));
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(defaultNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(defaultForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(defaultImportEnumExtension));
+
+    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
+    assertEqualsExactType("123", message.getExtension(defaultCordExtension));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}
+   * followed by {@code modifyRepeatedExtensions}.
+   */
+  public static void assertRepeatedExtensionsModified(
+      TestAllExtensionsOrBuilder message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtension, 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(repeatedForeignEnumExtension, 0));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(repeatedImportEnumExtension, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+    // Actually verify the second (modified) elements now.
+    assertEqualsExactType(501  , message.getExtension(repeatedInt32Extension   , 1));
+    assertEqualsExactType(502L , message.getExtension(repeatedInt64Extension   , 1));
+    assertEqualsExactType(503  , message.getExtension(repeatedUint32Extension  , 1));
+    assertEqualsExactType(504L , message.getExtension(repeatedUint64Extension  , 1));
+    assertEqualsExactType(505  , message.getExtension(repeatedSint32Extension  , 1));
+    assertEqualsExactType(506L , message.getExtension(repeatedSint64Extension  , 1));
+    assertEqualsExactType(507  , message.getExtension(repeatedFixed32Extension , 1));
+    assertEqualsExactType(508L , message.getExtension(repeatedFixed64Extension , 1));
+    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32Extension, 1));
+    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64Extension, 1));
+    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtension   , 1));
+    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtension  , 1));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 1));
+    assertEqualsExactType("515", message.getExtension(repeatedStringExtension  , 1));
+    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtension, 1));
+
+    assertEqualsExactType(517, message.getExtension(repeatedGroupExtension         , 1).getA());
+    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD());
+    assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(repeatedNestedEnumExtension, 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(repeatedForeignEnumExtension, 1));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(repeatedImportEnumExtension, 1));
+
+    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtension, 1));
+    assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1));
+  }
+
+  public static void setPackedExtensions(TestPackedExtensions.Builder message) {
+    message.addExtension(packedInt32Extension   , 601);
+    message.addExtension(packedInt64Extension   , 602L);
+    message.addExtension(packedUint32Extension  , 603);
+    message.addExtension(packedUint64Extension  , 604L);
+    message.addExtension(packedSint32Extension  , 605);
+    message.addExtension(packedSint64Extension  , 606L);
+    message.addExtension(packedFixed32Extension , 607);
+    message.addExtension(packedFixed64Extension , 608L);
+    message.addExtension(packedSfixed32Extension, 609);
+    message.addExtension(packedSfixed64Extension, 610L);
+    message.addExtension(packedFloatExtension   , 611F);
+    message.addExtension(packedDoubleExtension  , 612D);
+    message.addExtension(packedBoolExtension    , true);
+    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addExtension(packedInt32Extension   , 701);
+    message.addExtension(packedInt64Extension   , 702L);
+    message.addExtension(packedUint32Extension  , 703);
+    message.addExtension(packedUint64Extension  , 704L);
+    message.addExtension(packedSint32Extension  , 705);
+    message.addExtension(packedSint64Extension  , 706L);
+    message.addExtension(packedFixed32Extension , 707);
+    message.addExtension(packedFixed64Extension , 708L);
+    message.addExtension(packedSfixed32Extension, 709);
+    message.addExtension(packedSfixed64Extension, 710L);
+    message.addExtension(packedFloatExtension   , 711F);
+    message.addExtension(packedDoubleExtension  , 712D);
+    message.addExtension(packedBoolExtension    , false);
+    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAZ);
+  }
+
+  public static void assertPackedExtensionsSet(TestPackedExtensions message) {
+    Assert.assertEquals(2, message.getExtensionCount(packedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtension));
+    assertEqualsExactType(601  , message.getExtension(packedInt32Extension   , 0));
+    assertEqualsExactType(602L , message.getExtension(packedInt64Extension   , 0));
+    assertEqualsExactType(603  , message.getExtension(packedUint32Extension  , 0));
+    assertEqualsExactType(604L , message.getExtension(packedUint64Extension  , 0));
+    assertEqualsExactType(605  , message.getExtension(packedSint32Extension  , 0));
+    assertEqualsExactType(606L , message.getExtension(packedSint64Extension  , 0));
+    assertEqualsExactType(607  , message.getExtension(packedFixed32Extension , 0));
+    assertEqualsExactType(608L , message.getExtension(packedFixed64Extension , 0));
+    assertEqualsExactType(609  , message.getExtension(packedSfixed32Extension, 0));
+    assertEqualsExactType(610L , message.getExtension(packedSfixed64Extension, 0));
+    assertEqualsExactType(611F , message.getExtension(packedFloatExtension   , 0));
+    assertEqualsExactType(612D , message.getExtension(packedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(packedBoolExtension    , 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+                          message.getExtension(packedEnumExtension, 0));
+    assertEqualsExactType(701  , message.getExtension(packedInt32Extension   , 1));
+    assertEqualsExactType(702L , message.getExtension(packedInt64Extension   , 1));
+    assertEqualsExactType(703  , message.getExtension(packedUint32Extension  , 1));
+    assertEqualsExactType(704L , message.getExtension(packedUint64Extension  , 1));
+    assertEqualsExactType(705  , message.getExtension(packedSint32Extension  , 1));
+    assertEqualsExactType(706L , message.getExtension(packedSint64Extension  , 1));
+    assertEqualsExactType(707  , message.getExtension(packedFixed32Extension , 1));
+    assertEqualsExactType(708L , message.getExtension(packedFixed64Extension , 1));
+    assertEqualsExactType(709  , message.getExtension(packedSfixed32Extension, 1));
+    assertEqualsExactType(710L , message.getExtension(packedSfixed64Extension, 1));
+    assertEqualsExactType(711F , message.getExtension(packedFloatExtension   , 1));
+    assertEqualsExactType(712D , message.getExtension(packedDoubleExtension  , 1));
+    assertEqualsExactType(false, message.getExtension(packedBoolExtension    , 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+                          message.getExtension(packedEnumExtension, 1));
+  }
+
+  // =================================================================
+
+  /**
+   * Performs the same things that the methods of {@code TestUtil} do, but
+   * via the reflection interface.  This is its own class because it needs
+   * to know what descriptor to use.
+   */
+  public static class ReflectionTester {
+    private final Descriptors.Descriptor baseDescriptor;
+    private final ExtensionRegistry extensionRegistry;
+
+    private final Descriptors.FileDescriptor file;
+    private final Descriptors.FileDescriptor importFile;
+    private final Descriptors.FileDescriptor publicImportFile;
+
+    private final Descriptors.Descriptor optionalGroup;
+    private final Descriptors.Descriptor repeatedGroup;
+    private final Descriptors.Descriptor nestedMessage;
+    private final Descriptors.Descriptor foreignMessage;
+    private final Descriptors.Descriptor importMessage;
+    private final Descriptors.Descriptor publicImportMessage;
+
+    private final Descriptors.FieldDescriptor groupA;
+    private final Descriptors.FieldDescriptor repeatedGroupA;
+    private final Descriptors.FieldDescriptor nestedB;
+    private final Descriptors.FieldDescriptor foreignC;
+    private final Descriptors.FieldDescriptor importD;
+    private final Descriptors.FieldDescriptor importE;
+
+    private final Descriptors.EnumDescriptor nestedEnum;
+    private final Descriptors.EnumDescriptor foreignEnum;
+    private final Descriptors.EnumDescriptor importEnum;
+
+    private final Descriptors.EnumValueDescriptor nestedFoo;
+    private final Descriptors.EnumValueDescriptor nestedBar;
+    private final Descriptors.EnumValueDescriptor nestedBaz;
+    private final Descriptors.EnumValueDescriptor foreignFoo;
+    private final Descriptors.EnumValueDescriptor foreignBar;
+    private final Descriptors.EnumValueDescriptor foreignBaz;
+    private final Descriptors.EnumValueDescriptor importFoo;
+    private final Descriptors.EnumValueDescriptor importBar;
+    private final Descriptors.EnumValueDescriptor importBaz;
+
+    /**
+     * Construct a {@code ReflectionTester} that will expect messages using
+     * the given descriptor.
+     *
+     * Normally {@code baseDescriptor} should be a descriptor for the type
+     * {@code TestAllTypes}, defined in
+     * {@code google/protobuf/unittest.proto}.  However, if
+     * {@code extensionRegistry} is non-null, then {@code baseDescriptor} should
+     * be for {@code TestAllExtensions} instead, and instead of reading and
+     * writing normal fields, the tester will read and write extensions.
+     * All of {@code TestAllExtensions}' extensions must be registered in the
+     * registry.
+     */
+    public ReflectionTester(Descriptors.Descriptor baseDescriptor,
+                            ExtensionRegistry extensionRegistry) {
+      this.baseDescriptor = baseDescriptor;
+      this.extensionRegistry = extensionRegistry;
+
+      this.file = baseDescriptor.getFile();
+      Assert.assertEquals(1, file.getDependencies().size());
+      this.importFile = file.getDependencies().get(0);
+      this.publicImportFile = importFile.getDependencies().get(0);
+
+      Descriptors.Descriptor testAllTypes;
+      if (baseDescriptor.getName() == "TestAllTypes") {
+        testAllTypes = baseDescriptor;
+      } else {
+        testAllTypes = file.findMessageTypeByName("TestAllTypes");
+        Assert.assertNotNull(testAllTypes);
+      }
+
+      if (extensionRegistry == null) {
+        // Use testAllTypes, rather than baseDescriptor, to allow
+        // initialization using TestPackedTypes descriptors. These objects
+        // won't be used by the methods for packed fields.
+        this.optionalGroup =
+          testAllTypes.findNestedTypeByName("OptionalGroup");
+        this.repeatedGroup =
+          testAllTypes.findNestedTypeByName("RepeatedGroup");
+      } else {
+        this.optionalGroup =
+          file.findMessageTypeByName("OptionalGroup_extension");
+        this.repeatedGroup =
+          file.findMessageTypeByName("RepeatedGroup_extension");
+      }
+      this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
+      this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
+      this.importMessage = importFile.findMessageTypeByName("ImportMessage");
+      this.publicImportMessage = publicImportFile.findMessageTypeByName(
+          "PublicImportMessage");
+
+      this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
+      this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
+      this.importEnum = importFile.findEnumTypeByName("ImportEnum");
+
+      Assert.assertNotNull(optionalGroup );
+      Assert.assertNotNull(repeatedGroup );
+      Assert.assertNotNull(nestedMessage );
+      Assert.assertNotNull(foreignMessage);
+      Assert.assertNotNull(importMessage );
+      Assert.assertNotNull(nestedEnum    );
+      Assert.assertNotNull(foreignEnum   );
+      Assert.assertNotNull(importEnum    );
+
+      this.nestedB  = nestedMessage .findFieldByName("bb");
+      this.foreignC = foreignMessage.findFieldByName("c");
+      this.importD  = importMessage .findFieldByName("d");
+      this.importE  = publicImportMessage.findFieldByName("e");
+      this.nestedFoo = nestedEnum.findValueByName("FOO");
+      this.nestedBar = nestedEnum.findValueByName("BAR");
+      this.nestedBaz = nestedEnum.findValueByName("BAZ");
+      this.foreignFoo = foreignEnum.findValueByName("FOREIGN_FOO");
+      this.foreignBar = foreignEnum.findValueByName("FOREIGN_BAR");
+      this.foreignBaz = foreignEnum.findValueByName("FOREIGN_BAZ");
+      this.importFoo = importEnum.findValueByName("IMPORT_FOO");
+      this.importBar = importEnum.findValueByName("IMPORT_BAR");
+      this.importBaz = importEnum.findValueByName("IMPORT_BAZ");
+
+      this.groupA = optionalGroup.findFieldByName("a");
+      this.repeatedGroupA = repeatedGroup.findFieldByName("a");
+
+      Assert.assertNotNull(groupA        );
+      Assert.assertNotNull(repeatedGroupA);
+      Assert.assertNotNull(nestedB       );
+      Assert.assertNotNull(foreignC      );
+      Assert.assertNotNull(importD       );
+      Assert.assertNotNull(importE       );
+      Assert.assertNotNull(nestedFoo     );
+      Assert.assertNotNull(nestedBar     );
+      Assert.assertNotNull(nestedBaz     );
+      Assert.assertNotNull(foreignFoo    );
+      Assert.assertNotNull(foreignBar    );
+      Assert.assertNotNull(foreignBaz    );
+      Assert.assertNotNull(importFoo     );
+      Assert.assertNotNull(importBar     );
+      Assert.assertNotNull(importBaz     );
+    }
+
+    /**
+     * Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+     */
+    private Descriptors.FieldDescriptor f(String name) {
+      Descriptors.FieldDescriptor result;
+      if (extensionRegistry == null) {
+        result = baseDescriptor.findFieldByName(name);
+      } else {
+        result = file.findExtensionByName(name + "_extension");
+      }
+      Assert.assertNotNull(result);
+      return result;
+    }
+
+    /**
+     * Calls {@code parent.newBuilderForField()} or uses the
+     * {@code ExtensionRegistry} to find an appropriate builder, depending
+     * on what type is being tested.
+     */
+    private Message.Builder newBuilderForField(
+        Message.Builder parent, Descriptors.FieldDescriptor field) {
+      if (extensionRegistry == null) {
+        return parent.newBuilderForField(field);
+      } else {
+        ExtensionRegistry.ExtensionInfo extension =
+          extensionRegistry.findExtensionByNumber(field.getContainingType(),
+                                                  field.getNumber());
+        Assert.assertNotNull(extension);
+        Assert.assertNotNull(extension.defaultInstance);
+        return extension.defaultInstance.newBuilderForType();
+      }
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Set every field of {@code message} to the values expected by
+     * {@code assertAllFieldsSet()}, using the {@link Message.Builder}
+     * reflection interface.
+     */
+    void setAllFieldsViaReflection(Message.Builder message) {
+      message.setField(f("optional_int32"   ), 101 );
+      message.setField(f("optional_int64"   ), 102L);
+      message.setField(f("optional_uint32"  ), 103 );
+      message.setField(f("optional_uint64"  ), 104L);
+      message.setField(f("optional_sint32"  ), 105 );
+      message.setField(f("optional_sint64"  ), 106L);
+      message.setField(f("optional_fixed32" ), 107 );
+      message.setField(f("optional_fixed64" ), 108L);
+      message.setField(f("optional_sfixed32"), 109 );
+      message.setField(f("optional_sfixed64"), 110L);
+      message.setField(f("optional_float"   ), 111F);
+      message.setField(f("optional_double"  ), 112D);
+      message.setField(f("optional_bool"    ), true);
+      message.setField(f("optional_string"  ), "115");
+      message.setField(f("optional_bytes"   ), toBytes("116"));
+
+      message.setField(f("optionalgroup"),
+        newBuilderForField(message, f("optionalgroup"))
+               .setField(groupA, 117).build());
+      message.setField(f("optional_nested_message"),
+        newBuilderForField(message, f("optional_nested_message"))
+               .setField(nestedB, 118).build());
+      message.setField(f("optional_foreign_message"),
+        newBuilderForField(message, f("optional_foreign_message"))
+               .setField(foreignC, 119).build());
+      message.setField(f("optional_import_message"),
+        newBuilderForField(message, f("optional_import_message"))
+               .setField(importD, 120).build());
+      message.setField(f("optional_public_import_message"),
+        newBuilderForField(message, f("optional_public_import_message"))
+               .setField(importE, 126).build());
+      message.setField(f("optional_lazy_message"),
+        newBuilderForField(message, f("optional_lazy_message"))
+               .setField(nestedB, 127).build());
+
+      message.setField(f("optional_nested_enum" ),  nestedBaz);
+      message.setField(f("optional_foreign_enum"), foreignBaz);
+      message.setField(f("optional_import_enum" ),  importBaz);
+
+      message.setField(f("optional_string_piece" ), "124");
+      message.setField(f("optional_cord" ), "125");
+
+      // -----------------------------------------------------------------
+
+      message.addRepeatedField(f("repeated_int32"   ), 201 );
+      message.addRepeatedField(f("repeated_int64"   ), 202L);
+      message.addRepeatedField(f("repeated_uint32"  ), 203 );
+      message.addRepeatedField(f("repeated_uint64"  ), 204L);
+      message.addRepeatedField(f("repeated_sint32"  ), 205 );
+      message.addRepeatedField(f("repeated_sint64"  ), 206L);
+      message.addRepeatedField(f("repeated_fixed32" ), 207 );
+      message.addRepeatedField(f("repeated_fixed64" ), 208L);
+      message.addRepeatedField(f("repeated_sfixed32"), 209 );
+      message.addRepeatedField(f("repeated_sfixed64"), 210L);
+      message.addRepeatedField(f("repeated_float"   ), 211F);
+      message.addRepeatedField(f("repeated_double"  ), 212D);
+      message.addRepeatedField(f("repeated_bool"    ), true);
+      message.addRepeatedField(f("repeated_string"  ), "215");
+      message.addRepeatedField(f("repeated_bytes"   ), toBytes("216"));
+
+      message.addRepeatedField(f("repeatedgroup"),
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 217).build());
+      message.addRepeatedField(f("repeated_nested_message"),
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 218).build());
+      message.addRepeatedField(f("repeated_foreign_message"),
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 219).build());
+      message.addRepeatedField(f("repeated_import_message"),
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 220).build());
+      message.addRepeatedField(f("repeated_lazy_message"),
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 227).build());
+
+      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBar);
+      message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
+      message.addRepeatedField(f("repeated_import_enum" ),  importBar);
+
+      message.addRepeatedField(f("repeated_string_piece" ), "224");
+      message.addRepeatedField(f("repeated_cord" ), "225");
+
+      // Add a second one of each field.
+      message.addRepeatedField(f("repeated_int32"   ), 301 );
+      message.addRepeatedField(f("repeated_int64"   ), 302L);
+      message.addRepeatedField(f("repeated_uint32"  ), 303 );
+      message.addRepeatedField(f("repeated_uint64"  ), 304L);
+      message.addRepeatedField(f("repeated_sint32"  ), 305 );
+      message.addRepeatedField(f("repeated_sint64"  ), 306L);
+      message.addRepeatedField(f("repeated_fixed32" ), 307 );
+      message.addRepeatedField(f("repeated_fixed64" ), 308L);
+      message.addRepeatedField(f("repeated_sfixed32"), 309 );
+      message.addRepeatedField(f("repeated_sfixed64"), 310L);
+      message.addRepeatedField(f("repeated_float"   ), 311F);
+      message.addRepeatedField(f("repeated_double"  ), 312D);
+      message.addRepeatedField(f("repeated_bool"    ), false);
+      message.addRepeatedField(f("repeated_string"  ), "315");
+      message.addRepeatedField(f("repeated_bytes"   ), toBytes("316"));
+
+      message.addRepeatedField(f("repeatedgroup"),
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 317).build());
+      message.addRepeatedField(f("repeated_nested_message"),
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 318).build());
+      message.addRepeatedField(f("repeated_foreign_message"),
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 319).build());
+      message.addRepeatedField(f("repeated_import_message"),
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 320).build());
+      message.addRepeatedField(f("repeated_lazy_message"),
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 327).build());
+
+      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBaz);
+      message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
+      message.addRepeatedField(f("repeated_import_enum" ),  importBaz);
+
+      message.addRepeatedField(f("repeated_string_piece" ), "324");
+      message.addRepeatedField(f("repeated_cord" ), "325");
+
+      // -----------------------------------------------------------------
+
+      message.setField(f("default_int32"   ), 401 );
+      message.setField(f("default_int64"   ), 402L);
+      message.setField(f("default_uint32"  ), 403 );
+      message.setField(f("default_uint64"  ), 404L);
+      message.setField(f("default_sint32"  ), 405 );
+      message.setField(f("default_sint64"  ), 406L);
+      message.setField(f("default_fixed32" ), 407 );
+      message.setField(f("default_fixed64" ), 408L);
+      message.setField(f("default_sfixed32"), 409 );
+      message.setField(f("default_sfixed64"), 410L);
+      message.setField(f("default_float"   ), 411F);
+      message.setField(f("default_double"  ), 412D);
+      message.setField(f("default_bool"    ), false);
+      message.setField(f("default_string"  ), "415");
+      message.setField(f("default_bytes"   ), toBytes("416"));
+
+      message.setField(f("default_nested_enum" ),  nestedFoo);
+      message.setField(f("default_foreign_enum"), foreignFoo);
+      message.setField(f("default_import_enum" ),  importFoo);
+
+      message.setField(f("default_string_piece" ), "424");
+      message.setField(f("default_cord" ), "425");
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Modify the repeated fields of {@code message} to contain the values
+     * expected by {@code assertRepeatedFieldsModified()}, using the
+     * {@link Message.Builder} reflection interface.
+     */
+    void modifyRepeatedFieldsViaReflection(Message.Builder message) {
+      message.setRepeatedField(f("repeated_int32"   ), 1, 501 );
+      message.setRepeatedField(f("repeated_int64"   ), 1, 502L);
+      message.setRepeatedField(f("repeated_uint32"  ), 1, 503 );
+      message.setRepeatedField(f("repeated_uint64"  ), 1, 504L);
+      message.setRepeatedField(f("repeated_sint32"  ), 1, 505 );
+      message.setRepeatedField(f("repeated_sint64"  ), 1, 506L);
+      message.setRepeatedField(f("repeated_fixed32" ), 1, 507 );
+      message.setRepeatedField(f("repeated_fixed64" ), 1, 508L);
+      message.setRepeatedField(f("repeated_sfixed32"), 1, 509 );
+      message.setRepeatedField(f("repeated_sfixed64"), 1, 510L);
+      message.setRepeatedField(f("repeated_float"   ), 1, 511F);
+      message.setRepeatedField(f("repeated_double"  ), 1, 512D);
+      message.setRepeatedField(f("repeated_bool"    ), 1, true);
+      message.setRepeatedField(f("repeated_string"  ), 1, "515");
+      message.setRepeatedField(f("repeated_bytes"   ), 1, toBytes("516"));
+
+      message.setRepeatedField(f("repeatedgroup"), 1,
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 517).build());
+      message.setRepeatedField(f("repeated_nested_message"), 1,
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 518).build());
+      message.setRepeatedField(f("repeated_foreign_message"), 1,
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 519).build());
+      message.setRepeatedField(f("repeated_import_message"), 1,
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 520).build());
+      message.setRepeatedField(f("repeated_lazy_message"), 1,
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 527).build());
+
+      message.setRepeatedField(f("repeated_nested_enum" ), 1,  nestedFoo);
+      message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
+      message.setRepeatedField(f("repeated_import_enum" ), 1,  importFoo);
+
+      message.setRepeatedField(f("repeated_string_piece"), 1, "524");
+      message.setRepeatedField(f("repeated_cord"), 1, "525");
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Assert (using {@code junit.framework.Assert}} that all fields of
+     * {@code message} are set to the values assigned by {@code setAllFields},
+     * using the {@link Message} reflection interface.
+     */
+    public void assertAllFieldsSetViaReflection(MessageOrBuilder message) {
+      Assert.assertTrue(message.hasField(f("optional_int32"   )));
+      Assert.assertTrue(message.hasField(f("optional_int64"   )));
+      Assert.assertTrue(message.hasField(f("optional_uint32"  )));
+      Assert.assertTrue(message.hasField(f("optional_uint64"  )));
+      Assert.assertTrue(message.hasField(f("optional_sint32"  )));
+      Assert.assertTrue(message.hasField(f("optional_sint64"  )));
+      Assert.assertTrue(message.hasField(f("optional_fixed32" )));
+      Assert.assertTrue(message.hasField(f("optional_fixed64" )));
+      Assert.assertTrue(message.hasField(f("optional_sfixed32")));
+      Assert.assertTrue(message.hasField(f("optional_sfixed64")));
+      Assert.assertTrue(message.hasField(f("optional_float"   )));
+      Assert.assertTrue(message.hasField(f("optional_double"  )));
+      Assert.assertTrue(message.hasField(f("optional_bool"    )));
+      Assert.assertTrue(message.hasField(f("optional_string"  )));
+      Assert.assertTrue(message.hasField(f("optional_bytes"   )));
+
+      Assert.assertTrue(message.hasField(f("optionalgroup"           )));
+      Assert.assertTrue(message.hasField(f("optional_nested_message" )));
+      Assert.assertTrue(message.hasField(f("optional_foreign_message")));
+      Assert.assertTrue(message.hasField(f("optional_import_message" )));
+
+      Assert.assertTrue(
+        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_nested_message")))
+                         .hasField(nestedB));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .hasField(foreignC));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_import_message")))
+                         .hasField(importD));
+
+      Assert.assertTrue(message.hasField(f("optional_nested_enum" )));
+      Assert.assertTrue(message.hasField(f("optional_foreign_enum")));
+      Assert.assertTrue(message.hasField(f("optional_import_enum" )));
+
+      Assert.assertTrue(message.hasField(f("optional_string_piece")));
+      Assert.assertTrue(message.hasField(f("optional_cord")));
+
+      Assert.assertEquals(101  , message.getField(f("optional_int32"   )));
+      Assert.assertEquals(102L , message.getField(f("optional_int64"   )));
+      Assert.assertEquals(103  , message.getField(f("optional_uint32"  )));
+      Assert.assertEquals(104L , message.getField(f("optional_uint64"  )));
+      Assert.assertEquals(105  , message.getField(f("optional_sint32"  )));
+      Assert.assertEquals(106L , message.getField(f("optional_sint64"  )));
+      Assert.assertEquals(107  , message.getField(f("optional_fixed32" )));
+      Assert.assertEquals(108L , message.getField(f("optional_fixed64" )));
+      Assert.assertEquals(109  , message.getField(f("optional_sfixed32")));
+      Assert.assertEquals(110L , message.getField(f("optional_sfixed64")));
+      Assert.assertEquals(111F , message.getField(f("optional_float"   )));
+      Assert.assertEquals(112D , message.getField(f("optional_double"  )));
+      Assert.assertEquals(true , message.getField(f("optional_bool"    )));
+      Assert.assertEquals("115", message.getField(f("optional_string"  )));
+      Assert.assertEquals(toBytes("116"), message.getField(f("optional_bytes")));
+
+      Assert.assertEquals(117,
+        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+      Assert.assertEquals(118,
+        ((Message)message.getField(f("optional_nested_message")))
+                         .getField(nestedB));
+      Assert.assertEquals(119,
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .getField(foreignC));
+      Assert.assertEquals(120,
+        ((Message)message.getField(f("optional_import_message")))
+                         .getField(importD));
+      Assert.assertEquals(126,
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .getField(importE));
+      Assert.assertEquals(127,
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
+      Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
+      Assert.assertEquals( importBaz, message.getField(f("optional_import_enum" )));
+
+      Assert.assertEquals("124", message.getField(f("optional_string_piece")));
+      Assert.assertEquals("125", message.getField(f("optional_cord")));
+
+      // -----------------------------------------------------------------
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
+      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
+      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
+      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
+      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
+      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
+      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
+      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
+      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
+      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
+      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
+      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+      Assert.assertEquals(217,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(218,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+                         .getField(nestedB));
+      Assert.assertEquals(219,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+                         .getField(foreignC));
+      Assert.assertEquals(220,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+                         .getField(importD));
+      Assert.assertEquals(227,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+      Assert.assertEquals(301  , message.getRepeatedField(f("repeated_int32"   ), 1));
+      Assert.assertEquals(302L , message.getRepeatedField(f("repeated_int64"   ), 1));
+      Assert.assertEquals(303  , message.getRepeatedField(f("repeated_uint32"  ), 1));
+      Assert.assertEquals(304L , message.getRepeatedField(f("repeated_uint64"  ), 1));
+      Assert.assertEquals(305  , message.getRepeatedField(f("repeated_sint32"  ), 1));
+      Assert.assertEquals(306L , message.getRepeatedField(f("repeated_sint64"  ), 1));
+      Assert.assertEquals(307  , message.getRepeatedField(f("repeated_fixed32" ), 1));
+      Assert.assertEquals(308L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+      Assert.assertEquals(309  , message.getRepeatedField(f("repeated_sfixed32"), 1));
+      Assert.assertEquals(310L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+      Assert.assertEquals(311F , message.getRepeatedField(f("repeated_float"   ), 1));
+      Assert.assertEquals(312D , message.getRepeatedField(f("repeated_double"  ), 1));
+      Assert.assertEquals(false, message.getRepeatedField(f("repeated_bool"    ), 1));
+      Assert.assertEquals("315", message.getRepeatedField(f("repeated_string"  ), 1));
+      Assert.assertEquals(toBytes("316"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+      Assert.assertEquals(317,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(318,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+                         .getField(nestedB));
+      Assert.assertEquals(319,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+                         .getField(foreignC));
+      Assert.assertEquals(320,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+                         .getField(importD));
+      Assert.assertEquals(327,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
+      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
+      Assert.assertEquals( importBaz, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+      Assert.assertEquals("324", message.getRepeatedField(f("repeated_string_piece"), 1));
+      Assert.assertEquals("325", message.getRepeatedField(f("repeated_cord"), 1));
+
+      // -----------------------------------------------------------------
+
+      Assert.assertTrue(message.hasField(f("default_int32"   )));
+      Assert.assertTrue(message.hasField(f("default_int64"   )));
+      Assert.assertTrue(message.hasField(f("default_uint32"  )));
+      Assert.assertTrue(message.hasField(f("default_uint64"  )));
+      Assert.assertTrue(message.hasField(f("default_sint32"  )));
+      Assert.assertTrue(message.hasField(f("default_sint64"  )));
+      Assert.assertTrue(message.hasField(f("default_fixed32" )));
+      Assert.assertTrue(message.hasField(f("default_fixed64" )));
+      Assert.assertTrue(message.hasField(f("default_sfixed32")));
+      Assert.assertTrue(message.hasField(f("default_sfixed64")));
+      Assert.assertTrue(message.hasField(f("default_float"   )));
+      Assert.assertTrue(message.hasField(f("default_double"  )));
+      Assert.assertTrue(message.hasField(f("default_bool"    )));
+      Assert.assertTrue(message.hasField(f("default_string"  )));
+      Assert.assertTrue(message.hasField(f("default_bytes"   )));
+
+      Assert.assertTrue(message.hasField(f("default_nested_enum" )));
+      Assert.assertTrue(message.hasField(f("default_foreign_enum")));
+      Assert.assertTrue(message.hasField(f("default_import_enum" )));
+
+      Assert.assertTrue(message.hasField(f("default_string_piece")));
+      Assert.assertTrue(message.hasField(f("default_cord")));
+
+      Assert.assertEquals(401  , message.getField(f("default_int32"   )));
+      Assert.assertEquals(402L , message.getField(f("default_int64"   )));
+      Assert.assertEquals(403  , message.getField(f("default_uint32"  )));
+      Assert.assertEquals(404L , message.getField(f("default_uint64"  )));
+      Assert.assertEquals(405  , message.getField(f("default_sint32"  )));
+      Assert.assertEquals(406L , message.getField(f("default_sint64"  )));
+      Assert.assertEquals(407  , message.getField(f("default_fixed32" )));
+      Assert.assertEquals(408L , message.getField(f("default_fixed64" )));
+      Assert.assertEquals(409  , message.getField(f("default_sfixed32")));
+      Assert.assertEquals(410L , message.getField(f("default_sfixed64")));
+      Assert.assertEquals(411F , message.getField(f("default_float"   )));
+      Assert.assertEquals(412D , message.getField(f("default_double"  )));
+      Assert.assertEquals(false, message.getField(f("default_bool"    )));
+      Assert.assertEquals("415", message.getField(f("default_string"  )));
+      Assert.assertEquals(toBytes("416"), message.getField(f("default_bytes")));
+
+      Assert.assertEquals( nestedFoo, message.getField(f("default_nested_enum" )));
+      Assert.assertEquals(foreignFoo, message.getField(f("default_foreign_enum")));
+      Assert.assertEquals( importFoo, message.getField(f("default_import_enum" )));
+
+      Assert.assertEquals("424", message.getField(f("default_string_piece")));
+      Assert.assertEquals("425", message.getField(f("default_cord")));
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Assert (using {@code junit.framework.Assert}} that all fields of
+     * {@code message} are cleared, and that getting the fields returns their
+     * default values, using the {@link Message} reflection interface.
+     */
+    public void assertClearViaReflection(MessageOrBuilder message) {
+      // has_blah() should initially be false for all optional fields.
+      Assert.assertFalse(message.hasField(f("optional_int32"   )));
+      Assert.assertFalse(message.hasField(f("optional_int64"   )));
+      Assert.assertFalse(message.hasField(f("optional_uint32"  )));
+      Assert.assertFalse(message.hasField(f("optional_uint64"  )));
+      Assert.assertFalse(message.hasField(f("optional_sint32"  )));
+      Assert.assertFalse(message.hasField(f("optional_sint64"  )));
+      Assert.assertFalse(message.hasField(f("optional_fixed32" )));
+      Assert.assertFalse(message.hasField(f("optional_fixed64" )));
+      Assert.assertFalse(message.hasField(f("optional_sfixed32")));
+      Assert.assertFalse(message.hasField(f("optional_sfixed64")));
+      Assert.assertFalse(message.hasField(f("optional_float"   )));
+      Assert.assertFalse(message.hasField(f("optional_double"  )));
+      Assert.assertFalse(message.hasField(f("optional_bool"    )));
+      Assert.assertFalse(message.hasField(f("optional_string"  )));
+      Assert.assertFalse(message.hasField(f("optional_bytes"   )));
+
+      Assert.assertFalse(message.hasField(f("optionalgroup"           )));
+      Assert.assertFalse(message.hasField(f("optional_nested_message" )));
+      Assert.assertFalse(message.hasField(f("optional_foreign_message")));
+      Assert.assertFalse(message.hasField(f("optional_import_message" )));
+
+      Assert.assertFalse(message.hasField(f("optional_nested_enum" )));
+      Assert.assertFalse(message.hasField(f("optional_foreign_enum")));
+      Assert.assertFalse(message.hasField(f("optional_import_enum" )));
+
+      Assert.assertFalse(message.hasField(f("optional_string_piece")));
+      Assert.assertFalse(message.hasField(f("optional_cord")));
+
+      // Optional fields without defaults are set to zero or something like it.
+      Assert.assertEquals(0    , message.getField(f("optional_int32"   )));
+      Assert.assertEquals(0L   , message.getField(f("optional_int64"   )));
+      Assert.assertEquals(0    , message.getField(f("optional_uint32"  )));
+      Assert.assertEquals(0L   , message.getField(f("optional_uint64"  )));
+      Assert.assertEquals(0    , message.getField(f("optional_sint32"  )));
+      Assert.assertEquals(0L   , message.getField(f("optional_sint64"  )));
+      Assert.assertEquals(0    , message.getField(f("optional_fixed32" )));
+      Assert.assertEquals(0L   , message.getField(f("optional_fixed64" )));
+      Assert.assertEquals(0    , message.getField(f("optional_sfixed32")));
+      Assert.assertEquals(0L   , message.getField(f("optional_sfixed64")));
+      Assert.assertEquals(0F   , message.getField(f("optional_float"   )));
+      Assert.assertEquals(0D   , message.getField(f("optional_double"  )));
+      Assert.assertEquals(false, message.getField(f("optional_bool"    )));
+      Assert.assertEquals(""   , message.getField(f("optional_string"  )));
+      Assert.assertEquals(ByteString.EMPTY, message.getField(f("optional_bytes")));
+
+      // Embedded messages should also be clear.
+      Assert.assertFalse(
+        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_nested_message")))
+                         .hasField(nestedB));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .hasField(foreignC));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_import_message")))
+                         .hasField(importD));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .hasField(importE));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .hasField(nestedB));
+
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_nested_message")))
+                         .getField(nestedB));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .getField(foreignC));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_import_message")))
+                         .getField(importD));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .getField(importE));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .getField(nestedB));
+
+      // Enums without defaults are set to the first value in the enum.
+      Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
+      Assert.assertEquals(foreignFoo, message.getField(f("optional_foreign_enum")));
+      Assert.assertEquals( importFoo, message.getField(f("optional_import_enum" )));
+
+      Assert.assertEquals("", message.getField(f("optional_string_piece")));
+      Assert.assertEquals("", message.getField(f("optional_cord")));
+
+      // Repeated fields are empty.
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      // has_blah() should also be false for all default fields.
+      Assert.assertFalse(message.hasField(f("default_int32"   )));
+      Assert.assertFalse(message.hasField(f("default_int64"   )));
+      Assert.assertFalse(message.hasField(f("default_uint32"  )));
+      Assert.assertFalse(message.hasField(f("default_uint64"  )));
+      Assert.assertFalse(message.hasField(f("default_sint32"  )));
+      Assert.assertFalse(message.hasField(f("default_sint64"  )));
+      Assert.assertFalse(message.hasField(f("default_fixed32" )));
+      Assert.assertFalse(message.hasField(f("default_fixed64" )));
+      Assert.assertFalse(message.hasField(f("default_sfixed32")));
+      Assert.assertFalse(message.hasField(f("default_sfixed64")));
+      Assert.assertFalse(message.hasField(f("default_float"   )));
+      Assert.assertFalse(message.hasField(f("default_double"  )));
+      Assert.assertFalse(message.hasField(f("default_bool"    )));
+      Assert.assertFalse(message.hasField(f("default_string"  )));
+      Assert.assertFalse(message.hasField(f("default_bytes"   )));
+
+      Assert.assertFalse(message.hasField(f("default_nested_enum" )));
+      Assert.assertFalse(message.hasField(f("default_foreign_enum")));
+      Assert.assertFalse(message.hasField(f("default_import_enum" )));
+
+      Assert.assertFalse(message.hasField(f("default_string_piece" )));
+      Assert.assertFalse(message.hasField(f("default_cord" )));
+
+      // Fields with defaults have their default values (duh).
+      Assert.assertEquals( 41    , message.getField(f("default_int32"   )));
+      Assert.assertEquals( 42L   , message.getField(f("default_int64"   )));
+      Assert.assertEquals( 43    , message.getField(f("default_uint32"  )));
+      Assert.assertEquals( 44L   , message.getField(f("default_uint64"  )));
+      Assert.assertEquals(-45    , message.getField(f("default_sint32"  )));
+      Assert.assertEquals( 46L   , message.getField(f("default_sint64"  )));
+      Assert.assertEquals( 47    , message.getField(f("default_fixed32" )));
+      Assert.assertEquals( 48L   , message.getField(f("default_fixed64" )));
+      Assert.assertEquals( 49    , message.getField(f("default_sfixed32")));
+      Assert.assertEquals(-50L   , message.getField(f("default_sfixed64")));
+      Assert.assertEquals( 51.5F , message.getField(f("default_float"   )));
+      Assert.assertEquals( 52e3D , message.getField(f("default_double"  )));
+      Assert.assertEquals(true   , message.getField(f("default_bool"    )));
+      Assert.assertEquals("hello", message.getField(f("default_string"  )));
+      Assert.assertEquals(toBytes("world"), message.getField(f("default_bytes")));
+
+      Assert.assertEquals( nestedBar, message.getField(f("default_nested_enum" )));
+      Assert.assertEquals(foreignBar, message.getField(f("default_foreign_enum")));
+      Assert.assertEquals( importBar, message.getField(f("default_import_enum" )));
+
+      Assert.assertEquals("abc", message.getField(f("default_string_piece")));
+      Assert.assertEquals("123", message.getField(f("default_cord")));
+    }
+
+
+    // ---------------------------------------------------------------
+
+    public void assertRepeatedFieldsModifiedViaReflection(
+        MessageOrBuilder message) {
+      // ModifyRepeatedFields only sets the second repeated element of each
+      // field.  In addition to verifying this, we also verify that the first
+      // element and size were *not* modified.
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
+      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
+      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
+      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
+      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
+      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
+      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
+      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
+      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
+      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
+      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
+      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+      Assert.assertEquals(217,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(218,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+                         .getField(nestedB));
+      Assert.assertEquals(219,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+                         .getField(foreignC));
+      Assert.assertEquals(220,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+                         .getField(importD));
+      Assert.assertEquals(227,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+      Assert.assertEquals(501  , message.getRepeatedField(f("repeated_int32"   ), 1));
+      Assert.assertEquals(502L , message.getRepeatedField(f("repeated_int64"   ), 1));
+      Assert.assertEquals(503  , message.getRepeatedField(f("repeated_uint32"  ), 1));
+      Assert.assertEquals(504L , message.getRepeatedField(f("repeated_uint64"  ), 1));
+      Assert.assertEquals(505  , message.getRepeatedField(f("repeated_sint32"  ), 1));
+      Assert.assertEquals(506L , message.getRepeatedField(f("repeated_sint64"  ), 1));
+      Assert.assertEquals(507  , message.getRepeatedField(f("repeated_fixed32" ), 1));
+      Assert.assertEquals(508L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+      Assert.assertEquals(509  , message.getRepeatedField(f("repeated_sfixed32"), 1));
+      Assert.assertEquals(510L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+      Assert.assertEquals(511F , message.getRepeatedField(f("repeated_float"   ), 1));
+      Assert.assertEquals(512D , message.getRepeatedField(f("repeated_double"  ), 1));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 1));
+      Assert.assertEquals("515", message.getRepeatedField(f("repeated_string"  ), 1));
+      Assert.assertEquals(toBytes("516"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+      Assert.assertEquals(517,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(518,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+                         .getField(nestedB));
+      Assert.assertEquals(519,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+                         .getField(foreignC));
+      Assert.assertEquals(520,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+                         .getField(importD));
+      Assert.assertEquals(527,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
+      Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
+      Assert.assertEquals( importFoo, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+      Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1));
+      Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1));
+    }
+
+    public void setPackedFieldsViaReflection(Message.Builder message) {
+      message.addRepeatedField(f("packed_int32"   ), 601 );
+      message.addRepeatedField(f("packed_int64"   ), 602L);
+      message.addRepeatedField(f("packed_uint32"  ), 603 );
+      message.addRepeatedField(f("packed_uint64"  ), 604L);
+      message.addRepeatedField(f("packed_sint32"  ), 605 );
+      message.addRepeatedField(f("packed_sint64"  ), 606L);
+      message.addRepeatedField(f("packed_fixed32" ), 607 );
+      message.addRepeatedField(f("packed_fixed64" ), 608L);
+      message.addRepeatedField(f("packed_sfixed32"), 609 );
+      message.addRepeatedField(f("packed_sfixed64"), 610L);
+      message.addRepeatedField(f("packed_float"   ), 611F);
+      message.addRepeatedField(f("packed_double"  ), 612D);
+      message.addRepeatedField(f("packed_bool"    ), true);
+      message.addRepeatedField(f("packed_enum" ),  foreignBar);
+      // Add a second one of each field.
+      message.addRepeatedField(f("packed_int32"   ), 701 );
+      message.addRepeatedField(f("packed_int64"   ), 702L);
+      message.addRepeatedField(f("packed_uint32"  ), 703 );
+      message.addRepeatedField(f("packed_uint64"  ), 704L);
+      message.addRepeatedField(f("packed_sint32"  ), 705 );
+      message.addRepeatedField(f("packed_sint64"  ), 706L);
+      message.addRepeatedField(f("packed_fixed32" ), 707 );
+      message.addRepeatedField(f("packed_fixed64" ), 708L);
+      message.addRepeatedField(f("packed_sfixed32"), 709 );
+      message.addRepeatedField(f("packed_sfixed64"), 710L);
+      message.addRepeatedField(f("packed_float"   ), 711F);
+      message.addRepeatedField(f("packed_double"  ), 712D);
+      message.addRepeatedField(f("packed_bool"    ), false);
+      message.addRepeatedField(f("packed_enum" ),  foreignBaz);
+    }
+
+    public void assertPackedFieldsSetViaReflection(MessageOrBuilder message) {
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_enum"   )));
+      Assert.assertEquals(601  , message.getRepeatedField(f("packed_int32"   ), 0));
+      Assert.assertEquals(602L , message.getRepeatedField(f("packed_int64"   ), 0));
+      Assert.assertEquals(603  , message.getRepeatedField(f("packed_uint32"  ), 0));
+      Assert.assertEquals(604L , message.getRepeatedField(f("packed_uint64"  ), 0));
+      Assert.assertEquals(605  , message.getRepeatedField(f("packed_sint32"  ), 0));
+      Assert.assertEquals(606L , message.getRepeatedField(f("packed_sint64"  ), 0));
+      Assert.assertEquals(607  , message.getRepeatedField(f("packed_fixed32" ), 0));
+      Assert.assertEquals(608L , message.getRepeatedField(f("packed_fixed64" ), 0));
+      Assert.assertEquals(609  , message.getRepeatedField(f("packed_sfixed32"), 0));
+      Assert.assertEquals(610L , message.getRepeatedField(f("packed_sfixed64"), 0));
+      Assert.assertEquals(611F , message.getRepeatedField(f("packed_float"   ), 0));
+      Assert.assertEquals(612D , message.getRepeatedField(f("packed_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("packed_bool"    ), 0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("packed_enum" ),0));
+      Assert.assertEquals(701  , message.getRepeatedField(f("packed_int32"   ), 1));
+      Assert.assertEquals(702L , message.getRepeatedField(f("packed_int64"   ), 1));
+      Assert.assertEquals(703  , message.getRepeatedField(f("packed_uint32"  ), 1));
+      Assert.assertEquals(704L , message.getRepeatedField(f("packed_uint64"  ), 1));
+      Assert.assertEquals(705  , message.getRepeatedField(f("packed_sint32"  ), 1));
+      Assert.assertEquals(706L , message.getRepeatedField(f("packed_sint64"  ), 1));
+      Assert.assertEquals(707  , message.getRepeatedField(f("packed_fixed32" ), 1));
+      Assert.assertEquals(708L , message.getRepeatedField(f("packed_fixed64" ), 1));
+      Assert.assertEquals(709  , message.getRepeatedField(f("packed_sfixed32"), 1));
+      Assert.assertEquals(710L , message.getRepeatedField(f("packed_sfixed64"), 1));
+      Assert.assertEquals(711F , message.getRepeatedField(f("packed_float"   ), 1));
+      Assert.assertEquals(712D , message.getRepeatedField(f("packed_double"  ), 1));
+      Assert.assertEquals(false, message.getRepeatedField(f("packed_bool"    ), 1));
+      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("packed_enum" ),1));
+    }
+
+    /**
+     * Verifies that the reflection setters for the given.Builder object throw a
+     * NullPointerException if they are passed a null value.  Uses Assert to throw an
+     * appropriate assertion failure, if the condition is not verified.
+     */
+    public void assertReflectionSettersRejectNull(Message.Builder builder)
+        throws Exception {
+      try {
+        builder.setField(f("optional_string"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_bytes"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_enum"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_message"),
+                         (TestAllTypes.NestedMessage) null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_message"),
+                         (TestAllTypes.NestedMessage.Builder) null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      try {
+        builder.addRepeatedField(f("repeated_string"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_bytes"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_nested_enum"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_nested_message"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+    }
+
+    /**
+     * Verifies that the reflection repeated setters for the given Builder object throw a
+     * NullPointerException if they are passed a null value.  Uses Assert to throw an appropriate
+     * assertion failure, if the condition is not verified.
+     */
+    public void assertReflectionRepeatedSettersRejectNull(Message.Builder builder)
+        throws Exception {
+      builder.addRepeatedField(f("repeated_string"), "one");
+      try {
+        builder.setRepeatedField(f("repeated_string"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(f("repeated_bytes"), toBytes("one"));
+      try {
+        builder.setRepeatedField(f("repeated_bytes"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(f("repeated_nested_enum"), nestedBaz);
+      try {
+        builder.setRepeatedField(f("repeated_nested_enum"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(
+          f("repeated_nested_message"),
+          TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+      try {
+        builder.setRepeatedField(f("repeated_nested_message"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+    }
+  }
+
+  /**
+   * @param filePath The path relative to
+   * {@link #getTestDataDir}.
+   */
+  public static String readTextFromFile(String filePath) {
+    return readBytesFromFile(filePath).toStringUtf8();
+  }
+
+  private static File getTestDataDir() {
+    // Search each parent directory looking for "src/google/protobuf".
+    File ancestor = new File(".");
+    try {
+      ancestor = ancestor.getCanonicalFile();
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Couldn't get canonical name of working directory.", e);
+    }
+    while (ancestor != null && ancestor.exists()) {
+      if (new File(ancestor, "src/google/protobuf").exists()) {
+        return new File(ancestor, "src/google/protobuf/testdata");
+      }
+      ancestor = ancestor.getParentFile();
+    }
+
+    throw new RuntimeException(
+      "Could not find golden files.  This test must be run from within the " +
+      "protobuf source package so that it can read test data files from the " +
+      "C++ source tree: " + new File(".").getAbsolutePath());
+  }
+
+  /**
+   * @param filename The path relative to
+   * {@link #getTestDataDir}.
+   */
+  public static ByteString readBytesFromFile(String filename) {
+    File fullPath = new File(getTestDataDir(), filename);
+    try {
+      RandomAccessFile file = new RandomAccessFile(fullPath, "r");
+      byte[] content = new byte[(int) file.length()];
+      file.readFully(content);
+      return ByteString.copyFrom(content);
+    } catch (IOException e) {
+      // Throw a RuntimeException here so that we can call this function from
+      // static initializers.
+      throw new IllegalArgumentException(
+        "Couldn't read file: " + fullPath.getPath(), e);
+    }
+  }
+
+  /**
+   * Get the bytes of the "golden message".  This is a serialized TestAllTypes
+   * with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
+   * on disk rather than generated dynamically.  The file is actually generated
+   * by C++ code, so testing against it verifies compatibility with C++.
+   */
+  public static ByteString getGoldenMessage() {
+    if (goldenMessage == null) {
+      goldenMessage = readBytesFromFile("golden_message");
+    }
+    return goldenMessage;
+  }
+  private static ByteString goldenMessage = null;
+
+  /**
+   * Get the bytes of the "golden packed fields message".  This is a serialized
+   * TestPackedTypes with all fields set as they would be by
+   * {@link #setPackedFields(TestPackedTypes.Builder)}, but it is loaded from a
+   * file on disk rather than generated dynamically.  The file is actually
+   * generated by C++ code, so testing against it verifies compatibility with
+   * C++.
+   */
+  public static ByteString getGoldenPackedFieldsMessage() {
+    if (goldenPackedFieldsMessage == null) {
+      goldenPackedFieldsMessage =
+          readBytesFromFile("golden_packed_fields_message");
+    }
+    return goldenPackedFieldsMessage;
+  }
+  private static ByteString goldenPackedFieldsMessage = null;
+
+  public static abstract class HackMessage extends GeneratedMessage {
+    public interface MyInterface extends BuilderParent {
+    }
+  }
+  /**
+   * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
+   *
+   * @author jonp@google.com (Jon Perlow)
+   */
+  public static class MockBuilderParent
+      implements HackMessage.MyInterface {
+
+    private int invalidations;
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public void markDirty() {
+      invalidations++;
+    }
+
+    public int getInvalidationCount() {
+      return invalidations;
+    }
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TextFormatTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TextFormatTest.java
new file mode 100644
index 0000000..edcc890
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/TextFormatTest.java
@@ -0,0 +1,536 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import protobuf_unittest.UnittestProto.OneString;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+
+/**
+ * Test case for {@link TextFormat}.
+ *
+ * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
+ *
+ * @author wenboz@google.com (Wenbo Zhu)
+ */
+public class TextFormatTest extends TestCase {
+
+  // A basic string with different escapable characters for testing.
+  private final static String kEscapeTestString =
+      "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+          + "slashes \\";
+
+  // A representation of the above string with all the characters escaped.
+  private final static String kEscapeTestStringEscaped =
+      "\\\"A string with \\' characters \\n and \\r newlines "
+          + "and \\t tabs and \\001 slashes \\\\";
+
+  private static String allFieldsSetText = TestUtil.readTextFromFile(
+    "text_format_unittest_data.txt");
+  private static String allExtensionsSetText = TestUtil.readTextFromFile(
+    "text_format_unittest_extensions_data.txt");
+
+  private static String exoticText =
+    "repeated_int32: -1\n" +
+    "repeated_int32: -2147483648\n" +
+    "repeated_int64: -1\n" +
+    "repeated_int64: -9223372036854775808\n" +
+    "repeated_uint32: 4294967295\n" +
+    "repeated_uint32: 2147483648\n" +
+    "repeated_uint64: 18446744073709551615\n" +
+    "repeated_uint64: 9223372036854775808\n" +
+    "repeated_double: 123.0\n" +
+    "repeated_double: 123.5\n" +
+    "repeated_double: 0.125\n" +
+    "repeated_double: .125\n" +
+    "repeated_double: -.125\n" +
+    "repeated_double: 1.23E17\n" +
+    "repeated_double: 1.23E+17\n" +
+    "repeated_double: -1.23e-17\n" +
+    "repeated_double: .23e+17\n" +
+    "repeated_double: -.23E17\n" +
+    "repeated_double: 1.235E22\n" +
+    "repeated_double: 1.235E-18\n" +
+    "repeated_double: 123.456789\n" +
+    "repeated_double: Infinity\n" +
+    "repeated_double: -Infinity\n" +
+    "repeated_double: NaN\n" +
+    "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
+      "\\341\\210\\264\"\n" +
+    "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
+
+  private static String canonicalExoticText =
+      exoticText.replace(": .", ": 0.").replace(": -.", ": -0.")   // short-form double
+      .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16");
+
+  private String messageSetText =
+    "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+    "  i: 123\n" +
+    "}\n" +
+    "[protobuf_unittest.TestMessageSetExtension2] {\n" +
+    "  str: \"foo\"\n" +
+    "}\n";
+
+  /** Print TestAllTypes and compare with golden file. */
+  public void testPrintMessage() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllSet());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allFieldsSetText, javaText);
+  }
+
+  /** Print TestAllTypes as Builder and compare with golden file. */
+  public void testPrintMessageBuilder() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allFieldsSetText, javaText);
+  }
+
+  /** Print TestAllExtensions and compare with golden file. */
+  public void testPrintExtensions() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allExtensionsSetText, javaText);
+  }
+
+  // Creates an example unknown field set.
+  private UnknownFieldSet makeUnknownFieldSet() {
+    return UnknownFieldSet.newBuilder()
+        .addField(5,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .addFixed32(2)
+            .addFixed64(3)
+            .addLengthDelimited(ByteString.copyFromUtf8("4"))
+            .addGroup(
+                UnknownFieldSet.newBuilder()
+                .addField(10,
+                    UnknownFieldSet.Field.newBuilder()
+                    .addVarint(5)
+                    .build())
+                .build())
+            .build())
+        .addField(8,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .addVarint(2)
+            .addVarint(3)
+            .build())
+        .addField(15,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(0xABCDEF1234567890L)
+            .addFixed32(0xABCD1234)
+            .addFixed64(0xABCDEF1234567890L)
+            .build())
+        .build();
+  }
+
+  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" +
+      "  10: 5\n" +
+      "}\n" +
+      "8: 1\n" +
+      "8: 2\n" +
+      "8: 3\n" +
+      "15: 12379813812177893520\n" +
+      "15: 0xabcd1234\n" +
+      "15: 0xabcdef1234567890\n",
+      TextFormat.printToString(message));
+  }
+
+  public void testPrintField() throws Exception {
+    final FieldDescriptor dataField =
+      OneString.getDescriptor().findFieldByName("data");
+    assertEquals(
+      "data: \"test data\"\n",
+      TextFormat.printFieldToString(dataField, "test data"));
+
+    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.printFieldToString(optionalField, value));
+  }
+
+  /**
+   * Helper to construct a ByteString from a String containing only 8-bit
+   * characters.  The characters are converted directly to bytes, *not*
+   * encoded using UTF-8.
+   */
+  private ByteString bytes(String str) throws Exception {
+    return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
+  }
+
+  /**
+   * Helper to construct a ByteString from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private ByteString bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return ByteString.copyFrom(bytes);
+  }
+
+  public void testPrintExotic() throws Exception {
+    Message message = TestAllTypes.newBuilder()
+      // Signed vs. unsigned numbers.
+      .addRepeatedInt32 (-1)
+      .addRepeatedUint32(-1)
+      .addRepeatedInt64 (-1)
+      .addRepeatedUint64(-1)
+
+      .addRepeatedInt32 (1  << 31)
+      .addRepeatedUint32(1  << 31)
+      .addRepeatedInt64 (1l << 63)
+      .addRepeatedUint64(1l << 63)
+
+      // Floats of various precisions and exponents.
+      .addRepeatedDouble(123)
+      .addRepeatedDouble(123.5)
+      .addRepeatedDouble(0.125)
+      .addRepeatedDouble(.125)
+      .addRepeatedDouble(-.125)
+      .addRepeatedDouble(123e15)
+      .addRepeatedDouble(123e15)
+      .addRepeatedDouble(-1.23e-17)
+      .addRepeatedDouble(.23e17)
+      .addRepeatedDouble(-23e15)
+      .addRepeatedDouble(123.5e20)
+      .addRepeatedDouble(123.5e-20)
+      .addRepeatedDouble(123.456789)
+      .addRepeatedDouble(Double.POSITIVE_INFINITY)
+      .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+      .addRepeatedDouble(Double.NaN)
+
+      // Strings and bytes that needing escaping.
+      .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
+      .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
+      .build();
+
+    assertEquals(canonicalExoticText, message.toString());
+  }
+
+  public void testPrintMessageSet() throws Exception {
+    TestMessageSet messageSet =
+      TestMessageSet.newBuilder()
+        .setExtension(
+          TestMessageSetExtension1.messageSetExtension,
+          TestMessageSetExtension1.newBuilder().setI(123).build())
+        .setExtension(
+          TestMessageSetExtension2.messageSetExtension,
+          TestMessageSetExtension2.newBuilder().setStr("foo").build())
+        .build();
+
+    assertEquals(messageSetText, messageSet.toString());
+  }
+
+  // =================================================================
+
+  public void testParse() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(allFieldsSetText, builder);
+    TestUtil.assertAllFieldsSet(builder.build());
+  }
+
+  public void testParseReader() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(new StringReader(allFieldsSetText), builder);
+    TestUtil.assertAllFieldsSet(builder.build());
+  }
+
+  public void testParseExtensions() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TextFormat.merge(allExtensionsSetText,
+                     TestUtil.getExtensionRegistry(),
+                     builder);
+    TestUtil.assertAllExtensionsSet(builder.build());
+  }
+
+  public void testParseCompatibility() throws Exception {
+    String original = "repeated_float: inf\n" +
+                      "repeated_float: -inf\n" +
+                      "repeated_float: nan\n" +
+                      "repeated_float: inff\n" +
+                      "repeated_float: -inff\n" +
+                      "repeated_float: nanf\n" +
+                      "repeated_float: 1.0f\n" +
+                      "repeated_float: infinityf\n" +
+                      "repeated_float: -Infinityf\n" +
+                      "repeated_double: infinity\n" +
+                      "repeated_double: -infinity\n" +
+                      "repeated_double: nan\n";
+    String canonical =  "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_float: NaN\n" +
+                        "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_float: NaN\n" +
+                        "repeated_float: 1.0\n" +
+                        "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_double: Infinity\n" +
+                        "repeated_double: -Infinity\n" +
+                        "repeated_double: NaN\n";
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(original, builder);
+    assertEquals(canonical, builder.build().toString());
+  }
+
+  public void testParseExotic() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(exoticText, builder);
+
+    // Too lazy to check things individually.  Don't try to debug this
+    // if testPrintExotic() is failing.
+    assertEquals(canonicalExoticText, builder.build().toString());
+  }
+
+  public void testParseMessageSet() throws Exception {
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+    TextFormat.merge(messageSetText, 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());
+  }
+
+  public void testParseNumericEnum() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_nested_enum: 2", builder);
+    assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
+  }
+
+  public void testParseAngleBrackets() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("OptionalGroup: < a: 1 >", builder);
+    assertTrue(builder.hasOptionalGroup());
+    assertEquals(1, builder.getOptionalGroup().getA());
+  }
+
+  public void testParseComment() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(
+      "# this is a comment\n" +
+      "optional_int32: 1  # another comment\n" +
+      "optional_int64: 2\n" +
+      "# EOF comment", builder);
+    assertEquals(1, builder.getOptionalInt32());
+    assertEquals(2, builder.getOptionalInt64());
+  }
+
+  // =================================================================
+
+  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());
+  }
+
+  public void testParseLongString() throws Exception {
+    String longText =
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890";
+
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_string: \"" + longText + "\"", builder);
+    assertEquals(longText, builder.getOptionalString());
+  }
+
+  public void testParseBoolean() throws Exception {
+    String goodText =
+        "repeated_bool: t  repeated_bool : 0\n" +
+        "repeated_bool :f repeated_bool:1";
+    String goodTextCanonical =
+        "repeated_bool: true\n" +
+        "repeated_bool: false\n" +
+        "repeated_bool: false\n" +
+        "repeated_bool: true\n";
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(goodText, builder);
+    assertEquals(goodTextCanonical, builder.build().toString());
+
+    try {
+      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
+      TextFormat.merge("optional_bool:2", badBuilder);
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.ParseException e) {
+      // success
+    }
+    try {
+      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
+      TextFormat.merge("optional_bool: foo", badBuilder);
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.ParseException e) {
+      // success
+    }
+  }
+
+  public void testParseAdjacentStringLiterals() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
+    assertEquals("foocorgegrault", builder.getOptionalString());
+  }
+
+  public void testPrintFieldValue() throws Exception {
+    assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
+    assertPrintFieldValue("123.0",  123f, "repeated_float");
+    assertPrintFieldValue("123.0",  123d, "repeated_double");
+    assertPrintFieldValue("123",  123, "repeated_int32");
+    assertPrintFieldValue("123",  123L, "repeated_int64");
+    assertPrintFieldValue("true",  true, "repeated_bool");
+    assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32");
+    assertPrintFieldValue("18446744073709551615",  0xFFFFFFFFFFFFFFFFL,
+        "repeated_uint64");
+    assertPrintFieldValue("\"\\001\\002\\003\"",
+        ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes");
+  }
+
+  private void assertPrintFieldValue(String expect, Object value,
+      String fieldName) throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    StringBuilder sb = new StringBuilder();
+    TextFormat.printFieldValue(
+        TestAllTypes.getDescriptor().findFieldByName(fieldName),
+        value, sb);
+    assertEquals(expect, sb.toString());
+  }
+
+  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()));
+  }
+
+  public void testShortDebugString_unknown() {
+    assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+        + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
+        + " 0xabcdef1234567890",
+        TextFormat.shortDebugString(makeUnknownFieldSet()));
+  }
+
+  public void testPrintToUnicodeString() {
+    assertEquals(
+        "optional_string: \"abc\u3042efg\"\n" +
+        "optional_bytes: \"\\343\\201\\202\"\n" +
+        "repeated_string: \"\u3093XYZ\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("abc\u3042efg")
+            .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
+            .addRepeatedString("\u3093XYZ")
+            .build()));
+  }
+
+  public void testPrintToUnicodeString_unknown() {
+    assertEquals(
+        "1: \"\\343\\201\\202\"\n",
+        TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder()
+            .addField(1,
+                UnknownFieldSet.Field.newBuilder()
+                .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
+            .build()));
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnknownFieldSetTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnknownFieldSetTest.java
new file mode 100644
index 0000000..b9bfb69
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnknownFieldSetTest.java
@@ -0,0 +1,438 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests related to unknown field handling.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class UnknownFieldSetTest extends TestCase {
+  public void setUp() throws Exception {
+    descriptor = TestAllTypes.getDescriptor();
+    allFields = TestUtil.getAllSet();
+    allFieldsData = allFields.toByteString();
+    emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+    unknownFields = emptyMessage.getUnknownFields();
+  }
+
+  UnknownFieldSet.Field getField(String name) {
+    Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
+    assertNotNull(field);
+    return unknownFields.getField(field.getNumber());
+  }
+
+  // Constructs a protocol buffer which contains fields with all the same
+  // numbers as allFieldsData except that each field is some other wire
+  // type.
+  ByteString getBizarroData() throws Exception {
+    UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+    UnknownFieldSet.Field varintField =
+      UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+    UnknownFieldSet.Field fixed32Field =
+      UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+    for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+         unknownFields.asMap().entrySet()) {
+      if (entry.getValue().getVarintList().isEmpty()) {
+        // Original field is not a varint, so use a varint.
+        bizarroFields.addField(entry.getKey(), varintField);
+      } else {
+        // Original field *is* a varint, so use something else.
+        bizarroFields.addField(entry.getKey(), fixed32Field);
+      }
+    }
+
+    return bizarroFields.build().toByteString();
+  }
+
+  Descriptors.Descriptor descriptor;
+  TestAllTypes allFields;
+  ByteString allFieldsData;
+
+  // An empty message that has been parsed from allFieldsData.  So, it has
+  // unknown fields of every type.
+  TestEmptyMessage emptyMessage;
+  UnknownFieldSet unknownFields;
+
+  // =================================================================
+
+  public void testVarint() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(allFields.getOptionalInt32(),
+                 (long) field.getVarintList().get(0));
+  }
+
+  public void testFixed32() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_fixed32");
+    assertEquals(1, field.getFixed32List().size());
+    assertEquals(allFields.getOptionalFixed32(),
+                 (int) field.getFixed32List().get(0));
+  }
+
+  public void testFixed64() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_fixed64");
+    assertEquals(1, field.getFixed64List().size());
+    assertEquals(allFields.getOptionalFixed64(),
+                 (long) field.getFixed64List().get(0));
+  }
+
+  public void testLengthDelimited() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_bytes");
+    assertEquals(1, field.getLengthDelimitedList().size());
+    assertEquals(allFields.getOptionalBytes(),
+                 field.getLengthDelimitedList().get(0));
+  }
+
+  public void testGroup() throws Exception {
+    Descriptors.FieldDescriptor nestedFieldDescriptor =
+      TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
+    assertNotNull(nestedFieldDescriptor);
+
+    UnknownFieldSet.Field field = getField("optionalgroup");
+    assertEquals(1, field.getGroupList().size());
+
+    UnknownFieldSet group = field.getGroupList().get(0);
+    assertEquals(1, group.asMap().size());
+    assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
+
+    UnknownFieldSet.Field nestedField =
+      group.getField(nestedFieldDescriptor.getNumber());
+    assertEquals(1, nestedField.getVarintList().size());
+    assertEquals(allFields.getOptionalGroup().getA(),
+                 (long) nestedField.getVarintList().get(0));
+  }
+
+  public void testSerialize() throws Exception {
+    // Check that serializing the UnknownFieldSet produces the original data
+    // again.
+    ByteString data = emptyMessage.toByteString();
+    assertEquals(allFieldsData, data);
+  }
+
+  public void testCopyFrom() throws Exception {
+    TestEmptyMessage message =
+      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
+
+    assertEquals(emptyMessage.toString(), message.toString());
+  }
+
+  public void testMergeFrom() throws Exception {
+    TestEmptyMessage source =
+      TestEmptyMessage.newBuilder()
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(2,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(2).build())
+            .addField(3,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(4).build())
+            .build())
+        .build();
+    TestEmptyMessage destination =
+      TestEmptyMessage.newBuilder()
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(1,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(1).build())
+            .addField(3,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(3).build())
+            .build())
+        .mergeFrom(source)
+        .build();
+
+    assertEquals(
+      "1: 1\n" +
+      "2: 2\n" +
+      "3: 3\n" +
+      "3: 4\n",
+      destination.toString());
+  }
+
+  public void testClear() throws Exception {
+    UnknownFieldSet fields =
+      UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
+    assertTrue(fields.asMap().isEmpty());
+  }
+
+  public void testClearMessage() throws Exception {
+    TestEmptyMessage message =
+      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
+    assertEquals(0, message.getSerializedSize());
+  }
+
+  public void testParseKnownAndUnknown() throws Exception {
+    // Test mixing known and unknown fields when parsing.
+
+    UnknownFieldSet fields =
+      UnknownFieldSet.newBuilder(unknownFields)
+        .addField(123456,
+          UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
+        .build();
+
+    ByteString data = fields.toByteString();
+    TestAllTypes destination = TestAllTypes.parseFrom(data);
+
+    TestUtil.assertAllFieldsSet(destination);
+    assertEquals(1, destination.getUnknownFields().asMap().size());
+
+    UnknownFieldSet.Field field =
+      destination.getUnknownFields().getField(123456);
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(654321, (long) field.getVarintList().get(0));
+  }
+
+  public void testWrongTypeTreatedAsUnknown() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the debug strings
+    // should be the same.
+    assertEquals(emptyMessage.toString(), allTypesMessage.toString());
+  }
+
+  public void testUnknownExtensions() throws Exception {
+    // Make sure fields are properly parsed to the UnknownFieldSet even when
+    // they are declared as extension numbers.
+
+    TestEmptyMessageWithExtensions message =
+      TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
+
+    assertEquals(unknownFields.asMap().size(),
+                 message.getUnknownFields().asMap().size());
+    assertEquals(allFieldsData, message.toByteString());
+  }
+
+  public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing extensions.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllExtensions allExtensionsMessage =
+      TestAllExtensions.parseFrom(bizarroData);
+    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the debug strings
+    // should be the same.
+    assertEquals(emptyMessage.toString(),
+                 allExtensionsMessage.toString());
+  }
+
+  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);
+
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(singularField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+            .addVarint(5)   // not valid
+            .build())
+        .addField(repeatedField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+            .addVarint(4)   // not valid
+            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+            .addVarint(6)   // not valid
+            .build())
+        .build()
+        .toByteString();
+
+    {
+      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());
+    }
+
+    {
+      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());
+    }
+  }
+
+  public void testLargeVarint() throws Exception {
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(1,
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(0x7FFFFFFFFFFFFFFFL)
+            .build())
+        .build()
+        .toByteString();
+    UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
+    UnknownFieldSet.Field field = parsed.getField(1);
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
+  }
+
+  public void testEqualsAndHashCode() {
+    UnknownFieldSet.Field fixed32Field =
+        UnknownFieldSet.Field.newBuilder()
+            .addFixed32(1)
+            .build();
+    UnknownFieldSet.Field fixed64Field =
+        UnknownFieldSet.Field.newBuilder()
+            .addFixed64(1)
+            .build();
+    UnknownFieldSet.Field varIntField =
+        UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .build();
+    UnknownFieldSet.Field lengthDelimitedField =
+        UnknownFieldSet.Field.newBuilder()
+            .addLengthDelimited(ByteString.EMPTY)
+            .build();
+    UnknownFieldSet.Field groupField =
+        UnknownFieldSet.Field.newBuilder()
+            .addGroup(unknownFields)
+            .build();
+
+    UnknownFieldSet a =
+        UnknownFieldSet.newBuilder()
+            .addField(1, fixed32Field)
+            .build();
+    UnknownFieldSet b =
+        UnknownFieldSet.newBuilder()
+            .addField(1, fixed64Field)
+            .build();
+    UnknownFieldSet c =
+        UnknownFieldSet.newBuilder()
+            .addField(1, varIntField)
+            .build();
+    UnknownFieldSet d =
+        UnknownFieldSet.newBuilder()
+            .addField(1, lengthDelimitedField)
+            .build();
+    UnknownFieldSet e =
+        UnknownFieldSet.newBuilder()
+            .addField(1, groupField)
+            .build();
+
+    checkEqualsIsConsistent(a);
+    checkEqualsIsConsistent(b);
+    checkEqualsIsConsistent(c);
+    checkEqualsIsConsistent(d);
+    checkEqualsIsConsistent(e);
+
+    checkNotEqual(a, b);
+    checkNotEqual(a, c);
+    checkNotEqual(a, d);
+    checkNotEqual(a, e);
+    checkNotEqual(b, c);
+    checkNotEqual(b, d);
+    checkNotEqual(b, e);
+    checkNotEqual(c, d);
+    checkNotEqual(c, e);
+    checkNotEqual(d, e);
+  }
+
+  /**
+   * Asserts that the given field sets are not equal and have different
+   * hash codes.
+   *
+   * @warning It's valid for non-equal objects to have the same hash code, so
+   *   this test is stricter than it needs to be. However, this should happen
+   *   relatively rarely.
+   */
+  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));
+
+    assertFalse(
+        String.format("%s should have a different hash code from %s", s1, s2),
+        s1.hashCode() == 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);
+
+    // 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());
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnmodifiableLazyStringListTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnmodifiableLazyStringListTest.java
new file mode 100644
index 0000000..cb75d74
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/UnmodifiableLazyStringListTest.java
@@ -0,0 +1,153 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import junit.framework.TestCase;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Tests for {@link UnmodifiableLazyStringList}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class UnmodifiableLazyStringListTest extends TestCase {
+
+  private static String STRING_A = "A";
+  private static String STRING_B = "B";
+  private static String STRING_C = "C";
+
+  private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
+  private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
+  private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
+
+  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));
+  }
+
+  public void testModifyMethods() {
+    LazyStringArrayList rawList = createSampleList();
+    UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
+
+    try {
+      list.remove(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(3, list.size());
+
+    try {
+      list.add(STRING_B);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(3, list.size());
+
+    try {
+      list.set(1, STRING_B);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
+  public void testIterator() {
+    LazyStringArrayList rawList = createSampleList();
+    UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
+
+    Iterator<String> iter = list.iterator();
+    int count = 0;
+    while (iter.hasNext()) {
+      iter.next();
+      count++;
+      try {
+        iter.remove();
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+    assertEquals(3, count);
+
+  }
+
+  public void testListIterator() {
+    LazyStringArrayList rawList = createSampleList();
+    UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
+
+    ListIterator<String> iter = list.listIterator();
+    int count = 0;
+    while (iter.hasNext()) {
+      iter.next();
+      count++;
+      try {
+        iter.remove();
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+      try {
+        iter.set("bar");
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+      try {
+        iter.add("bar");
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+    assertEquals(3, count);
+
+  }
+
+  private LazyStringArrayList createSampleList() {
+    LazyStringArrayList rawList = new LazyStringArrayList();
+    rawList.add(STRING_A);
+    rawList.add(STRING_B);
+    rawList.add(STRING_C);
+    return rawList;
+  }
+}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/WireFormatTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/WireFormatTest.java
new file mode 100644
index 0000000..7452872
--- /dev/null
+++ b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/WireFormatTest.java
@@ -0,0 +1,465 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.test;
+import com.google.protobuf.*;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+
+/**
+ * Tests related to parsing and serialization.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class WireFormatTest extends TestCase {
+  public void testSerialization() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializationPacked() throws Exception {
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+    TestUtil.assertPackedFieldsSet(message2);
+  }
+
+  public void testSerializeExtensions() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+    // it should work.
+
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializePackedExtensions() throws Exception {
+    // TestPackedTypes and TestPackedExtensions should have compatible wire
+    // formats; check that they serialize to the same string.
+    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    TestPackedTypes message2 = TestUtil.getPackedSet();
+    ByteString rawBytes2 = message2.toByteString();
+
+    assertEquals(rawBytes, rawBytes2);
+  }
+
+  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,
+    // since getSerializedSize() was never invoked.
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    // Directly construct a CodedOutputStream around the actual OutputStream,
+    // in case writeTo(OutputStream output) invokes getSerializedSize();
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
+
+    message.writeTo(codedOutput);
+
+    codedOutput.flush();
+
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(
+        outputStream.toByteArray());
+
+    TestUtil.assertPackedFieldsSet(message2);
+  }
+
+  public void testParseExtensions() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+    // it should work.
+
+    TestAllTypes message = TestUtil.getAllSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestAllExtensions message2 =
+      TestAllExtensions.parseFrom(rawBytes, registry);
+
+    TestUtil.assertAllExtensionsSet(message2);
+  }
+
+  public void testParsePackedExtensions() throws Exception {
+    // Ensure that packed extensions can be properly parsed.
+    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestPackedExtensions message2 =
+        TestPackedExtensions.parseFrom(rawBytes, registry);
+
+    TestUtil.assertPackedExtensionsSet(message2);
+  }
+
+  public void testExtensionsSerializedSize() throws Exception {
+    assertEquals(TestUtil.getAllSet().getSerializedSize(),
+                 TestUtil.getAllExtensionsSet().getSerializedSize());
+  }
+
+  public void testSerializeDelimited() throws Exception {
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    TestUtil.getAllSet().writeDelimitedTo(output);
+    output.write(12);
+    TestUtil.getPackedSet().writeDelimitedTo(output);
+    output.write(34);
+
+    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
+
+    TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
+    assertEquals(12, input.read());
+    TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
+    assertEquals(34, input.read());
+    assertEquals(-1, input.read());
+
+    // We're at EOF, so parsing again should return null.
+    assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
+  }
+
+  private void assertFieldsInOrder(ByteString data) throws Exception {
+    CodedInputStream input = data.newCodedInput();
+    int previousTag = 0;
+
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+
+      assertTrue(tag > previousTag);
+      previousTag = tag;
+      input.skipField(tag);
+    }
+  }
+
+  public void testInterleavedFieldsAndExtensions() throws Exception {
+    // Tests that fields are written in order even when extension ranges
+    // are interleaved with field numbers.
+    ByteString data =
+      TestFieldOrderings.newBuilder()
+        .setMyInt(1)
+        .setMyString("foo")
+        .setMyFloat(1.0F)
+        .setExtension(UnittestProto.myExtensionInt, 23)
+        .setExtension(UnittestProto.myExtensionString, "bar")
+        .build().toByteString();
+    assertFieldsInOrder(data);
+
+    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+    ByteString dynamic_data =
+      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+        .setField(descriptor.findFieldByName("my_int"), 1L)
+        .setField(descriptor.findFieldByName("my_string"), "foo")
+        .setField(descriptor.findFieldByName("my_float"), 1.0F)
+        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+        .build().toByteString();
+    assertFieldsInOrder(dynamic_data);
+  }
+
+  private ExtensionRegistry getTestFieldOrderingsRegistry() {
+    ExtensionRegistry result = ExtensionRegistry.newInstance();
+    result.add(UnittestProto.myExtensionInt);
+    result.add(UnittestProto.myExtensionString);
+    return result;
+  }
+
+  public void testParseMultipleExtensionRanges() throws Exception {
+    // Make sure we can parse a message that contains multiple extensions
+    // ranges.
+    TestFieldOrderings source =
+      TestFieldOrderings.newBuilder()
+        .setMyInt(1)
+        .setMyString("foo")
+        .setMyFloat(1.0F)
+        .setExtension(UnittestProto.myExtensionInt, 23)
+        .setExtension(UnittestProto.myExtensionString, "bar")
+        .build();
+    TestFieldOrderings dest =
+      TestFieldOrderings.parseFrom(source.toByteString(),
+                                   getTestFieldOrderingsRegistry());
+    assertEquals(source, dest);
+  }
+
+  public void testParseMultipleExtensionRangesDynamic() throws Exception {
+    // Same as above except with DynamicMessage.
+    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+    DynamicMessage source =
+      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+        .setField(descriptor.findFieldByName("my_int"), 1L)
+        .setField(descriptor.findFieldByName("my_string"), "foo")
+        .setField(descriptor.findFieldByName("my_float"), 1.0F)
+        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+        .build();
+    DynamicMessage dest =
+      DynamicMessage.parseFrom(descriptor, source.toByteString(),
+                               getTestFieldOrderingsRegistry());
+    assertEquals(source, dest);
+  }
+
+  private static final int UNKNOWN_TYPE_ID = 1550055;
+  private static final int TYPE_ID_1 =
+    TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
+  private static final int TYPE_ID_2 =
+    TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
+
+  public void testSerializeMessageSetEagerly() throws Exception {
+    testSerializeMessageSetWithFlag(true);
+  }
+
+  public void testSerializeMessageSetNotEagerly() throws Exception {
+    testSerializeMessageSetWithFlag(false);
+  }
+
+  private void testSerializeMessageSetWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    // Set up a TestMessageSet with two known messages and an unknown one.
+    TestMessageSet messageSet =
+      TestMessageSet.newBuilder()
+        .setExtension(
+          TestMessageSetExtension1.messageSetExtension,
+          TestMessageSetExtension1.newBuilder().setI(123).build())
+        .setExtension(
+          TestMessageSetExtension2.messageSetExtension,
+          TestMessageSetExtension2.newBuilder().setStr("foo").build())
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(UNKNOWN_TYPE_ID,
+              UnknownFieldSet.Field.newBuilder()
+                .addLengthDelimited(ByteString.copyFromUtf8("bar"))
+                .build())
+            .build())
+        .build();
+
+    ByteString data = messageSet.toByteString();
+
+    // Parse back using RawMessageSet and check the contents.
+    RawMessageSet raw = RawMessageSet.parseFrom(data);
+
+    assertTrue(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());
+
+    TestMessageSetExtension1 message1 =
+      TestMessageSetExtension1.parseFrom(
+        raw.getItem(0).getMessage().toByteArray());
+    assertEquals(123, message1.getI());
+
+    TestMessageSetExtension2 message2 =
+      TestMessageSetExtension2.parseFrom(
+        raw.getItem(1).getMessage().toByteArray());
+    assertEquals("foo", message2.getStr());
+
+    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+  }
+
+  public void testParseMessageSetEagerly() throws Exception {
+    testParseMessageSetWithFlag(true);
+  }
+
+  public void testParseMessageSetNotEagerly()throws Exception {
+    testParseMessageSetWithFlag(false);
+  }
+
+  private void testParseMessageSetWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    // Set up a RawMessageSet with two known messages and an unknown one.
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_2)
+            .setMessage(
+              TestMessageSetExtension2.newBuilder()
+                .setStr("foo")
+                .build().toByteString())
+            .build())
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(UNKNOWN_TYPE_ID)
+            .setMessage(ByteString.copyFromUtf8("bar"))
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // 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());
+
+    // 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));
+
+    UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
+    assertEquals(1, field.getLengthDelimitedList().size());
+    assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
+  }
+
+  public void testParseMessageSetExtensionEagerly() throws Exception {
+    testParseMessageSetExtensionWithFlag(true);
+  }
+
+  public void testParseMessageSetExtensionNotEagerly() throws Exception {
+    testParseMessageSetExtensionWithFlag(false);
+  }
+
+  private void testParseMessageSetExtensionWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+    // Set up a RawMessageSet with a known messages.
+    int TYPE_ID_1 =
+        TestMessageSetExtension1
+            .getDescriptor().getExtensions().get(0).getNumber();
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // Parse as a TestMessageSet and check the contents.
+    TestMessageSet messageSet =
+        TestMessageSet.parseFrom(data, extensionRegistry);
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
+    testMergeLazyMessageSetExtensionWithFlag(true);
+  }
+
+  public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
+    testMergeLazyMessageSetExtensionWithFlag(false);
+  }
+
+  private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+    // Set up a RawMessageSet with a known messages.
+    int TYPE_ID_1 =
+        TestMessageSetExtension1
+            .getDescriptor().getExtensions().get(0).getNumber();
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // Parse as a TestMessageSet and store value into lazy field
+    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());
+  }
+}
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
index ab415db..1d11f13 100644
--- a/java/core/generate-test-sources-build.xml
+++ b/java/core/generate-test-sources-build.xml
@@ -5,6 +5,7 @@
         <arg value="--proto_path=${protobuf.source.dir}"/>
         <arg value="--proto_path=${test.proto.dir}"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
@@ -18,6 +19,7 @@
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/deprecated_file.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
@@ -37,7 +39,8 @@
         <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_lite_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
     </exec>
-</project>
\ No newline at end of file
+</project>
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 74d5ead..067749c 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-2</version>
+    <version>3.6.1</version>
   </parent>
 
   <artifactId>protobuf-java</artifactId>
@@ -22,14 +22,17 @@
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymockclassextension</artifactId>
+      <scope>test</scope>
     </dependency>
   </dependencies>
 
@@ -92,11 +95,34 @@
 
       <!-- Add the generated sources to the build -->
       <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
-          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
-        </configuration>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-generated-sources</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${generated.sources.dir}</source>
+              </sources>
+            </configuration>
+          </execution>
+          <execution>
+            <id>add-generated-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <goals>
+              <goal>add-test-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${generated.testsources.dir}</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
       </plugin>
 
       <!-- OSGI bundle configuration -->
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 9f418f2..fc3c2a5 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -32,9 +32,9 @@
 
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
 import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Internal.EnumLite;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
@@ -50,17 +50,51 @@
  *
  * @author kenton@google.com Kenton Varda
  */
-public abstract class AbstractMessage extends AbstractMessageLite
-                                      implements Message {
+public abstract class AbstractMessage
+    // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
+    extends AbstractMessageLite
+    implements Message {
+
+  @Override
   public boolean isInitialized() {
     return MessageReflection.isInitialized(this);
   }
 
+  /**
+   * Interface for the parent of a Builder that allows the builder to
+   * communicate invalidations back to the parent for use when using nested
+   * builders.
+   */
+  protected interface BuilderParent {
 
+    /**
+     * A builder becomes dirty whenever a field is modified -- including fields
+     * in nested builders -- and becomes clean when build() is called.  Thus,
+     * when a builder becomes dirty, all its parents become dirty as well, and
+     * when it becomes clean, all its children become clean.  The dirtiness
+     * state is used to invalidate certain cached values.
+     * <br>
+     * To this end, a builder calls markDirty() on its parent whenever it
+     * transitions from clean to dirty.  The parent must propagate this call to
+     * its own parent, unless it was already dirty, in which case the
+     * grandparent must necessarily already be dirty as well.  The parent can
+     * only transition back to "clean" after calling build() on all children.
+     */
+    void markDirty();
+  }
+
+  /** Create a nested builder. */
+  protected Message.Builder newBuilderForType(BuilderParent parent) {
+    throw new UnsupportedOperationException("Nested builder is not supported for this type.");
+  }
+
+
+  @Override
   public List<String> findInitializationErrors() {
     return MessageReflection.findMissingFields(this);
   }
 
+  @Override
   public String getInitializationErrorString() {
     return MessageReflection.delimitWithCommas(findInitializationErrors());
   }
@@ -83,12 +117,24 @@
     return TextFormat.printToString(this);
   }
 
+  @Override
   public void writeTo(final CodedOutputStream output) throws IOException {
     MessageReflection.writeMessageTo(this, getAllFields(), output, false);
   }
 
   protected int memoizedSize = -1;
 
+  @Override
+  int getMemoizedSerializedSize() {
+    return memoizedSize;
+  }
+
+  @Override
+  void setMemoizedSerializedSize(int size) {
+    memoizedSize = size;
+  }
+
+  @Override
   public int getSerializedSize() {
     int size = memoizedSize;
     if (size != -1) {
@@ -127,7 +173,7 @@
     }
     return hash;
   }
-  
+
   private static ByteString toByteString(Object value) {
     if (value instanceof byte[]) {
       return ByteString.copyFrom((byte[]) value);
@@ -135,7 +181,7 @@
       return (ByteString) value;
     }
   }
- 
+
   /**
    * Compares two bytes fields. The parameters must be either a byte array or a
    * ByteString object. They can be of different type though.
@@ -146,7 +192,7 @@
     }
     return toByteString(a).equals(toByteString(b));
   }
-  
+
   /**
    * Converts a list of MapEntry messages into a Map used for equals() and
    * hashCode().
@@ -177,7 +223,7 @@
     }
     return result;
   }
-  
+
   /**
    * Compares two map fields. The parameters must be a list of MapEntry
    * messages.
@@ -188,13 +234,13 @@
     Map mb = convertMapEntryListToMap((List) b);
     return MapFieldLite.equals(ma, mb);
   }
-  
+
   /**
    * Compares two set of fields.
    * This method is used to implement {@link AbstractMessage#equals(Object)}
    * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
    * of bytes fields because immutable messages and mutable messages use
-   * different Java type to reprensent a bytes field and this method should be
+   * different Java type to represent a bytes field and this method should be
    * able to compare immutable messages, mutable messages and also an immutable
    * message to a mutable message.
    */
@@ -240,7 +286,7 @@
     }
     return true;
   }
-  
+
   /**
    * Calculates the hash code of a map field. {@code value} must be a list of
    * MapEntry messages.
@@ -288,12 +334,16 @@
    * other methods.
    */
   @SuppressWarnings("unchecked")
-  public static abstract class Builder<BuilderType extends Builder>
-      extends AbstractMessageLite.Builder<BuilderType>
+  public static abstract class Builder<BuilderType extends Builder<BuilderType>>
+      extends AbstractMessageLite.Builder
       implements Message.Builder {
     // The compiler produces an error if this is not declared explicitly.
+    // Method isn't abstract to bypass Java 1.6 compiler issue:
+    //     http://bugs.java.com/view_bug.do?bug_id=6908259
     @Override
-    public abstract BuilderType clone();
+    public BuilderType clone() {
+      throw new UnsupportedOperationException("clone() should be implemented in subclasses.");
+    }
 
     /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
     @Override
@@ -314,6 +364,7 @@
       throw new UnsupportedOperationException("clearOneof() is not implemented.");
     }
 
+    @Override
     public BuilderType clear() {
       for (final Map.Entry<FieldDescriptor, Object> entry :
            getAllFields().entrySet()) {
@@ -322,15 +373,27 @@
       return (BuilderType) this;
     }
 
+    @Override
     public List<String> findInitializationErrors() {
       return MessageReflection.findMissingFields(this);
     }
 
+    @Override
     public String getInitializationErrorString() {
       return MessageReflection.delimitWithCommas(findInitializationErrors());
     }
 
+    @Override
+    protected BuilderType internalMergeFrom(AbstractMessageLite other) {
+      return mergeFrom((Message) other);
+    }
+
+    @Override
     public BuilderType mergeFrom(final Message other) {
+      return mergeFrom(other, other.getAllFields());
+    }
+    
+    BuilderType mergeFrom(final Message other, Map<FieldDescriptor, Object> allFields) {
       if (other.getDescriptorForType() != getDescriptorForType()) {
         throw new IllegalArgumentException(
           "mergeFrom(Message) can only merge messages of the same type.");
@@ -345,8 +408,7 @@
       // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
       //   which allows people to make secure deep copies of messages.
 
-      for (final Map.Entry<FieldDescriptor, Object> entry :
-           other.getAllFields().entrySet()) {
+      for (final Map.Entry<FieldDescriptor, Object> entry : allFields.entrySet()) {
         final FieldDescriptor field = entry.getKey();
         if (field.isRepeated()) {
           for (final Object element : (List)entry.getValue()) {
@@ -384,8 +446,12 @@
         final CodedInputStream input,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
+      boolean discardUnknown =
+          getDescriptorForType().getFile().getSyntax() == Syntax.PROTO3
+              ? input.shouldDiscardUnknownFieldsProto3()
+              : input.shouldDiscardUnknownFields();
       final UnknownFieldSet.Builder unknownFields =
-        UnknownFieldSet.newBuilder(getUnknownFields());
+          discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
       while (true) {
         final int tag = input.readTag();
         if (tag == 0) {
@@ -403,10 +469,13 @@
           break;
         }
       }
-      setUnknownFields(unknownFields.build());
+      if (unknownFields != null) {
+        setUnknownFields(unknownFields.build());
+      }
       return (BuilderType) this;
     }
 
+    @Override
     public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
       setUnknownFields(
         UnknownFieldSet.newBuilder(getUnknownFields())
@@ -415,17 +484,19 @@
       return (BuilderType) this;
     }
 
+    @Override
     public Message.Builder getFieldBuilder(final FieldDescriptor field) {
       throw new UnsupportedOperationException(
           "getFieldBuilder() called on an unsupported message type.");
     }
 
-    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
-        int index) {
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
       throw new UnsupportedOperationException(
           "getRepeatedFieldBuilder() called on an unsupported message type.");
     }
 
+    @Override
     public String toString() {
       return TextFormat.printToString(this);
     }
@@ -440,6 +511,31 @@
           MessageReflection.findMissingFields(message));
     }
 
+    /**
+     * Used to support nested builders and called to mark this builder as clean.
+     * Clean builders will propagate the {@link BuilderParent#markDirty()} event
+     * to their parent builders, while dirty builders will not, as their parents
+     * should be dirty already.
+     *
+     * NOTE: Implementations that don't support nested builders don't need to
+     * override this method.
+     */
+    void markClean() {
+      throw new IllegalStateException("Should be overridden by subclasses.");
+    }
+
+    /**
+     * Used to support nested builders and called when this nested builder is
+     * no longer used by its parent builder and should release the reference
+     * to its parent builder.
+     *
+     * NOTE: Implementations that don't support nested builders don't need to
+     * override this method.
+     */
+    void dispose() {
+      throw new IllegalStateException("Should be overridden by subclasses.");
+    }
+
     // ===============================================================
     // The following definitions seem to be required in order to make javac
     // not produce weird errors like:
@@ -462,7 +558,7 @@
     @Override
     public BuilderType mergeFrom(final ByteString data)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data);
+      return (BuilderType) super.mergeFrom(data);
     }
 
     @Override
@@ -470,20 +566,20 @@
         final ByteString data,
         final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, extensionRegistry);
+      return (BuilderType) super.mergeFrom(data, extensionRegistry);
     }
 
     @Override
     public BuilderType mergeFrom(final byte[] data)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data);
+      return (BuilderType) super.mergeFrom(data);
     }
 
     @Override
     public BuilderType mergeFrom(
         final byte[] data, final int off, final int len)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, off, len);
+      return (BuilderType) super.mergeFrom(data, off, len);
     }
 
     @Override
@@ -491,7 +587,7 @@
         final byte[] data,
         final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, extensionRegistry);
+      return (BuilderType) super.mergeFrom(data, extensionRegistry);
     }
 
     @Override
@@ -499,13 +595,13 @@
         final byte[] data, final int off, final int len,
         final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, off, len, extensionRegistry);
+      return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
     }
 
     @Override
     public BuilderType mergeFrom(final InputStream input)
         throws IOException {
-      return super.mergeFrom(input);
+      return (BuilderType) super.mergeFrom(input);
     }
 
     @Override
@@ -513,7 +609,7 @@
         final InputStream input,
         final ExtensionRegistryLite extensionRegistry)
         throws IOException {
-      return super.mergeFrom(input, extensionRegistry);
+      return (BuilderType) super.mergeFrom(input, extensionRegistry);
     }
 
     @Override
@@ -530,4 +626,44 @@
       return super.mergeDelimitedFrom(input, extensionRegistry);
     }
   }
+
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashLong(long n) {
+    return (int) (n ^ (n >>> 32));
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashBoolean(boolean b) {
+    return b ? 1231 : 1237;
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashEnum(EnumLite e) {
+    return e.getNumber();
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashEnumList(List<? extends EnumLite> list) {
+    int hash = 1;
+    for (EnumLite e : list) {
+      hash = 31 * hash + hashEnum(e);
+    }
+    return hash;
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 1238498..b22bbaa 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -30,11 +30,15 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.Internal.checkNotNull;
+
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * A partial implementation of the {@link MessageLite} interface which
@@ -43,9 +47,12 @@
  *
  * @author kenton@google.com Kenton Varda
  */
-public abstract class AbstractMessageLite implements MessageLite {
+public abstract class AbstractMessageLite<
+    MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+    BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
+        implements MessageLite {
   protected int memoizedHashCode = 0;
-
+  @Override
   public ByteString toByteString() {
     try {
       final ByteString.CodedBuilder out =
@@ -53,12 +60,11 @@
       writeTo(out.getCodedOutput());
       return out.build();
     } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a ByteString threw an IOException (should " +
-        "never happen).", e);
+      throw new RuntimeException(getSerializingExceptionMessage("ByteString"), e);
     }
   }
 
+  @Override
   public byte[] toByteArray() {
     try {
       final byte[] result = new byte[getSerializedSize()];
@@ -67,12 +73,11 @@
       output.checkNoSpaceLeft();
       return result;
     } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a byte array threw an IOException " +
-        "(should never happen).", e);
+      throw new RuntimeException(getSerializingExceptionMessage("byte array"), e);
     }
   }
 
+  @Override
   public void writeTo(final OutputStream output) throws IOException {
     final int bufferSize =
         CodedOutputStream.computePreferredBufferSize(getSerializedSize());
@@ -82,6 +87,7 @@
     codedOutput.flush();
   }
 
+  @Override
   public void writeDelimitedTo(final OutputStream output) throws IOException {
     final int serialized = getSerializedSize();
     final int bufferSize = CodedOutputStream.computePreferredBufferSize(
@@ -93,6 +99,16 @@
     codedOutput.flush();
   }
 
+  // We'd like these to be abstract but some folks are extending this class directly. They shouldn't
+  // be doing that and they should feel bad.
+  int getMemoizedSerializedSize() {
+    throw new UnsupportedOperationException();
+  }
+
+  void setMemoizedSerializedSize(int size) {
+    throw new UnsupportedOperationException();
+  }
+
 
   /**
    * Package private helper method for AbstractParser to create
@@ -102,6 +118,11 @@
     return new UninitializedMessageException(this);
   }
 
+  private String getSerializingExceptionMessage(String target) {
+    return "Serializing " + getClass().getName() + " to a " + target
+        + " threw an IOException (should never happen).";
+  }
+
   protected static void checkByteStringIsUtf8(ByteString byteString)
       throws IllegalArgumentException {
     if (!byteString.isValidUtf8()) {
@@ -109,36 +130,43 @@
     }
   }
 
-  protected static <T> void addAll(final Iterable<T> values,
-      final Collection<? super T> list) {
+  // For binary compatibility
+  @Deprecated
+  protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
+    Builder.addAll(values, (List) list);
+  }
+
+  protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
     Builder.addAll(values, list);
   }
-  
+
   /**
    * A partial implementation of the {@link Message.Builder} interface which
    * implements as many methods of that interface as possible in terms of
    * other methods.
    */
   @SuppressWarnings("unchecked")
-  public static abstract class Builder<BuilderType extends Builder>
+  public abstract static class Builder<
+      MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+      BuilderType extends Builder<MessageType, BuilderType>>
       implements MessageLite.Builder {
     // The compiler produces an error if this is not declared explicitly.
     @Override
     public abstract BuilderType clone();
 
-    public BuilderType mergeFrom(final CodedInputStream input)
-                                 throws IOException {
+    @Override
+    public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
       return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
     }
 
     // Re-defined here for return type covariance.
+    @Override
     public abstract BuilderType mergeFrom(
-        final CodedInputStream input,
-        final ExtensionRegistryLite extensionRegistry)
+        final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
         throws IOException;
 
-    public BuilderType mergeFrom(final ByteString data)
-        throws InvalidProtocolBufferException {
+    @Override
+    public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input = data.newCodedInput();
         mergeFrom(input);
@@ -147,15 +175,13 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
       }
     }
 
+    @Override
     public BuilderType mergeFrom(
-        final ByteString data,
-        final ExtensionRegistryLite extensionRegistry)
+        final ByteString data, final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input = data.newCodedInput();
@@ -165,20 +191,18 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
       }
     }
 
-    public BuilderType mergeFrom(final byte[] data)
-        throws InvalidProtocolBufferException {
+    @Override
+    public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
       return mergeFrom(data, 0, data.length);
     }
 
-    public BuilderType mergeFrom(final byte[] data, final int off,
-                                 final int len)
-                                 throws InvalidProtocolBufferException {
+    @Override
+    public BuilderType mergeFrom(final byte[] data, final int off, final int len)
+        throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input =
             CodedInputStream.newInstance(data, off, len);
@@ -188,21 +212,21 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
       }
     }
 
-    public BuilderType mergeFrom(
-        final byte[] data,
-        final ExtensionRegistryLite extensionRegistry)
+    @Override
+    public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       return mergeFrom(data, 0, data.length, extensionRegistry);
     }
 
+    @Override
     public BuilderType mergeFrom(
-        final byte[] data, final int off, final int len,
+        final byte[] data,
+        final int off,
+        final int len,
         final ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       try {
@@ -214,12 +238,11 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
       }
     }
 
+    @Override
     public BuilderType mergeFrom(final InputStream input) throws IOException {
       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
       mergeFrom(codedInput);
@@ -227,10 +250,9 @@
       return (BuilderType) this;
     }
 
+    @Override
     public BuilderType mergeFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
+        final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
       mergeFrom(codedInput, extensionRegistry);
       codedInput.checkLastTagWas(0);
@@ -292,10 +314,9 @@
       }
     }
 
+    @Override
     public boolean mergeDelimitedFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
+        final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
       final int firstByte = input.read();
       if (firstByte == -1) {
         return false;
@@ -306,12 +327,49 @@
       return true;
     }
 
-    public boolean mergeDelimitedFrom(final InputStream input)
-        throws IOException {
+    @Override
+    public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
       return mergeDelimitedFrom(input,
           ExtensionRegistryLite.getEmptyRegistry());
     }
 
+    @Override
+    @SuppressWarnings("unchecked") // isInstance takes care of this
+    public BuilderType mergeFrom(final MessageLite other) {
+      if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+        throw new IllegalArgumentException(
+            "mergeFrom(MessageLite) can only merge messages of the same type.");
+      }
+
+      return internalMergeFrom((MessageType) other);
+    }
+
+    protected abstract BuilderType internalMergeFrom(MessageType message);
+
+    private String getReadingExceptionMessage(String target) {
+      return "Reading " + getClass().getName() + " from a " + target
+          + " threw an IOException (should never happen).";
+    }
+
+    // We check nulls as we iterate to avoid iterating over values twice.
+    private static <T> void addAllCheckingNulls(Iterable<T> values, List<? super T> list) {
+      if (list instanceof ArrayList && values instanceof Collection) {
+        ((ArrayList<T>) list).ensureCapacity(list.size() + ((Collection<T>) values).size());
+      }
+      int begin = list.size();
+      for (T value : values) {
+        if (value == null) {
+          // encountered a null value so we must undo our modifications prior to throwing
+          String message = "Element at index " + (list.size() - begin) + " is null.";
+          for (int i = list.size() - 1; i >= begin; i--) {
+            list.remove(i);
+          }
+          throw new NullPointerException(message);
+        }
+        list.add(value);
+      }
+    }
+
     /**
      * Construct an UninitializedMessageException reporting missing fields in
      * the given message.
@@ -321,41 +379,50 @@
       return new UninitializedMessageException(message);
     }
 
+    // For binary compatibility.
+    @Deprecated
+    protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
+      addAll(values, (List<T>) list);
+    }
+
     /**
-     * Adds the {@code values} to the {@code list}.  This is a helper method
-     * used by generated code.  Users should ignore it.
+     * Adds the {@code values} to the {@code list}. This is a helper method used by generated code.
+     * Users should ignore it.
      *
-     * @throws NullPointerException if {@code values} or any of the elements of
-     * {@code values} is null. When that happens, some elements of
-     * {@code values} may have already been added to the result {@code list}.
+     * @throws NullPointerException if {@code values} or any of the elements of {@code values} is
+     *     null.
      */
-    protected static <T> void addAll(final Iterable<T> values,
-                                     final Collection<? super T> list) {
-      if (values == null) {
-        throw new NullPointerException();
-      }
+    protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
+      checkNotNull(values);
       if (values instanceof LazyStringList) {
         // For StringOrByteStringLists, check the underlying elements to avoid
         // forcing conversions of ByteStrings to Strings.
-        checkForNullValues(((LazyStringList) values).getUnderlyingElements());
-        list.addAll((Collection<T>) values);
-      } else if (values instanceof Collection) {
-        checkForNullValues(values);
-        list.addAll((Collection<T>) values);
-      } else {
-        for (final T value : values) {
+        // TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
+        // if even possible to hit this condition as all protobuf methods check for null first,
+        // right?
+        List<?> lazyValues = ((LazyStringList) values).getUnderlyingElements();
+        LazyStringList lazyList = (LazyStringList) list;
+        int begin = list.size();
+        for (Object value : lazyValues) {
           if (value == null) {
-            throw new NullPointerException();
+            // encountered a null value so we must undo our modifications prior to throwing
+            String message = "Element at index " + (lazyList.size() - begin) + " is null.";
+            for (int i = lazyList.size() - 1; i >= begin; i--) {
+              lazyList.remove(i);
+            }
+            throw new NullPointerException(message);
           }
-          list.add(value);
+          if (value instanceof ByteString) {
+            lazyList.add((ByteString) value);
+          } else {
+            lazyList.add((String) value);
+          }
         }
-      }
-    }
-
-    private static void checkForNullValues(final Iterable<?> values) {
-      for (final Object value : values) {
-        if (value == null) {
-          throw new NullPointerException();
+      } else {
+        if (values instanceof PrimitiveNonBoxingCollection) {
+          list.addAll((Collection<T>) values);
+        } else {
+          addAllCheckingNulls(values, list);
         }
       }
     }
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
index 1a4c631..ba570e3 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractParser.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
@@ -31,9 +31,9 @@
 package com.google.protobuf;
 
 import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
 
 /**
  * A partial implementation of the {@link Parser} interface which implements
@@ -78,26 +78,27 @@
   private static final ExtensionRegistryLite EMPTY_REGISTRY
       = ExtensionRegistryLite.getEmptyRegistry();
 
+  @Override
   public MessageType parsePartialFrom(CodedInputStream input)
       throws InvalidProtocolBufferException {
     return parsePartialFrom(input, EMPTY_REGISTRY);
   }
 
-  public MessageType parseFrom(CodedInputStream input,
-                               ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(
         parsePartialFrom(input, extensionRegistry));
   }
 
-  public MessageType parseFrom(CodedInputStream input)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException {
     return parseFrom(input, EMPTY_REGISTRY);
   }
 
-  public MessageType parsePartialFrom(ByteString data,
-                                      ExtensionRegistryLite extensionRegistry)
-    throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
     MessageType message;
     try {
       CodedInputStream input = data.newCodedInput();
@@ -113,24 +114,49 @@
     }
   }
 
-  public MessageType parsePartialFrom(ByteString data)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException {
     return parsePartialFrom(data, EMPTY_REGISTRY);
   }
 
-  public MessageType parseFrom(ByteString data,
-                               ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
   }
 
-  public MessageType parseFrom(ByteString data)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException {
     return parseFrom(data, EMPTY_REGISTRY);
   }
 
-  public MessageType parsePartialFrom(byte[] data, int off, int len,
-                                      ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    MessageType message;
+    try {
+      CodedInputStream input = CodedInputStream.newInstance(data);
+      message = parsePartialFrom(input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
+
+    return checkMessageInitialized(message);
+  }
+
+  @Override
+  public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException {
+    return parseFrom(data, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(
+      byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     try {
       CodedInputStream input = CodedInputStream.newInstance(data, off, len);
@@ -146,47 +172,50 @@
     }
   }
 
+  @Override
   public MessageType parsePartialFrom(byte[] data, int off, int len)
       throws InvalidProtocolBufferException {
     return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
   }
 
-  public MessageType parsePartialFrom(byte[] data,
-                                      ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return parsePartialFrom(data, 0, data.length, extensionRegistry);
   }
 
-  public MessageType parsePartialFrom(byte[] data)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException {
     return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
   }
 
-  public MessageType parseFrom(byte[] data, int off, int len,
-                               ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(
+      byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(
         parsePartialFrom(data, off, len, extensionRegistry));
   }
 
+  @Override
   public MessageType parseFrom(byte[] data, int off, int len)
       throws InvalidProtocolBufferException {
     return parseFrom(data, off, len, EMPTY_REGISTRY);
   }
 
-  public MessageType parseFrom(byte[] data,
-                               ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return parseFrom(data, 0, data.length, extensionRegistry);
   }
 
-  public MessageType parseFrom(byte[] data)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException {
     return parseFrom(data, EMPTY_REGISTRY);
   }
 
-  public MessageType parsePartialFrom(InputStream input,
-                                      ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     CodedInputStream codedInput = CodedInputStream.newInstance(input);
     MessageType message = parsePartialFrom(codedInput, extensionRegistry);
@@ -198,26 +227,26 @@
     return message;
   }
 
-  public MessageType parsePartialFrom(InputStream input)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException {
     return parsePartialFrom(input, EMPTY_REGISTRY);
   }
 
-  public MessageType parseFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(
         parsePartialFrom(input, extensionRegistry));
   }
 
-  public MessageType parseFrom(InputStream input)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException {
     return parseFrom(input, EMPTY_REGISTRY);
   }
 
+  @Override
   public MessageType parsePartialDelimitedFrom(
-      InputStream input,
-      ExtensionRegistryLite extensionRegistry)
+      InputStream input, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     int size;
     try {
@@ -227,27 +256,27 @@
       }
       size = CodedInputStream.readRawVarint32(firstByte, input);
     } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage());
+      throw new InvalidProtocolBufferException(e);
     }
     InputStream limitedInput = new LimitedInputStream(input, size);
     return parsePartialFrom(limitedInput, extensionRegistry);
   }
 
+  @Override
   public MessageType parsePartialDelimitedFrom(InputStream input)
       throws InvalidProtocolBufferException {
     return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
   }
 
-  public MessageType parseDelimitedFrom(
-      InputStream input,
-      ExtensionRegistryLite extensionRegistry)
+  @Override
+  public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(
         parsePartialDelimitedFrom(input, extensionRegistry));
   }
 
-  public MessageType parseDelimitedFrom(InputStream input)
-      throws InvalidProtocolBufferException {
+  @Override
+  public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException {
     return parseDelimitedFrom(input, EMPTY_REGISTRY);
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
index bb6446b..b17db6e 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
@@ -34,19 +34,25 @@
 
 import java.util.AbstractList;
 import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
 
 /**
  * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
- * methods are check if the list is mutable before proceeding. Subclasses must invoke
+ * methods must check if the list is mutable before proceeding. Subclasses must invoke
  * {@link #ensureIsMutable()} manually when overriding those methods.
+ * <p>
+ * This implementation assumes all subclasses are array based, supporting random access.
  */
 abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
 
+  protected static final int DEFAULT_CAPACITY = 10;
+
   /**
    * Whether or not this list is modifiable.
    */
   private boolean isMutable;
-  
+
   /**
    * Constructs a mutable list by default.
    */
@@ -55,6 +61,44 @@
   }
 
   @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof List)) {
+      return false;
+    }
+    // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator
+    // based approach in our super class. Otherwise our index based approach will avoid those
+    // allocations.
+    if (!(o instanceof RandomAccess)) {
+      return super.equals(o);
+    }
+
+    List<?> other = (List<?>) o;
+    final int size = size();
+    if (size != other.size()) {
+      return false;
+    }
+    for (int i = 0; i < size; i++) {
+      if (!get(i).equals(other.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    final int size = size();
+    int hashCode = 1;
+    for (int i = 0; i < size; i++) {
+      hashCode = (31 * hashCode) + get(i).hashCode();
+    }
+    return hashCode;
+  }
+
+  @Override
   public boolean add(E e) {
     ensureIsMutable();
     return super.add(e);
diff --git a/java/core/src/main/java/com/google/protobuf/Android.java b/java/core/src/main/java/com/google/protobuf/Android.java
new file mode 100644
index 0000000..cad5478
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Android.java
@@ -0,0 +1,57 @@
+// 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;
+
+final class Android {
+
+  private static final Class<?> MEMORY_CLASS = getClassForName("libcore.io.Memory");
+  private static final boolean IS_ROBOLECTRIC =
+      getClassForName("org.robolectric.Robolectric") != null;
+
+  /** Returns {@code true} if running on an Android device. */
+  static boolean isOnAndroidDevice() {
+    return MEMORY_CLASS != null && !IS_ROBOLECTRIC;
+  }
+
+  /** Returns the memory class or {@code null} if not on Android device. */
+  static Class<?> getMemoryClass() {
+    return MEMORY_CLASS;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static <T> Class<T> getClassForName(String name) {
+    try {
+      return (Class<T>) Class.forName(name);
+    } catch (Throwable e) {
+      return null;
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 70e042f..4d7a972 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -30,37 +30,35 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.BooleanList;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.BooleanList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.RandomAccess;
 
 /**
  * An implementation of {@link BooleanList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class BooleanArrayList
-    extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess {
-  
-  private static final int DEFAULT_CAPACITY = 10;
-  
+final class BooleanArrayList extends AbstractProtobufList<Boolean>
+    implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
+
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static BooleanArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private boolean[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -71,35 +69,70 @@
    * Constructs a new mutable {@code BooleanArrayList} with default capacity.
    */
   BooleanArrayList() {
-    this(DEFAULT_CAPACITY);
+    this(new boolean[DEFAULT_CAPACITY], 0);
   }
 
   /**
-   * Constructs a new mutable {@code BooleanArrayList} with the provided capacity.
+   * Constructs a new mutable {@code BooleanArrayList}
+   * containing the same elements as {@code other}.
    */
-  BooleanArrayList(int capacity) {
-    array = new boolean[capacity];
-    size = 0;
+  private BooleanArrayList(boolean[] other, int size) {
+    array = other;
+    this.size = size;
   }
 
-  /**
-   * Constructs a new mutable {@code BooleanArrayList} containing the same elements as
-   * {@code other}.
-   */
-  BooleanArrayList(List<Boolean> other) {
-    if (other instanceof BooleanArrayList) {
-      BooleanArrayList list = (BooleanArrayList) other;
-      array = list.array.clone();
-      size = list.size;
-    } else {
-      size = other.size();
-      array = new boolean[size];
-      for (int i = 0; i < size; i++) {
-        array[i] = other.get(i);
+  @Override
+  protected void removeRange(int fromIndex, int toIndex) {
+    ensureIsMutable();
+    if (toIndex < fromIndex) {
+      throw new IndexOutOfBoundsException("toIndex < fromIndex");
+    }
+
+    System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+    size -= (toIndex - fromIndex);
+    modCount++;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof BooleanArrayList)) {
+      return super.equals(o);
+    }
+    BooleanArrayList other = (BooleanArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+
+    final boolean[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
       }
     }
+
+    return true;
   }
-  
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Internal.hashBoolean(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public BooleanList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new BooleanArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
   @Override
   public Boolean get(int index) {
     return getBoolean(index);
@@ -151,7 +184,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -159,10 +192,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       boolean[] newArray = new boolean[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -176,38 +209,36 @@
   @Override
   public boolean addAll(Collection<? extends Boolean> collection) {
     ensureIsMutable();
-    
-    if (collection == null) {
-      throw new NullPointerException();
-    }
-    
+
+    checkNotNull(collection);
+
     // We specialize when adding another BooleanArrayList to avoid boxing elements.
     if (!(collection instanceof BooleanArrayList)) {
       return super.addAll(collection);
     }
-    
+
     BooleanArrayList list = (BooleanArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -227,7 +258,9 @@
     ensureIsMutable();
     ensureIndexInRange(index);
     boolean value = array[index];
-    System.arraycopy(array, index + 1, array, index, size - index);
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index);
+    }
     size--;
     modCount++;
     return value;
@@ -236,7 +269,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
new file mode 100644
index 0000000..6157a52
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
@@ -0,0 +1,185 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s.
+ */
+final class ByteBufferWriter {
+  private ByteBufferWriter() {}
+
+  /**
+   * Minimum size for a cached buffer. This prevents us from allocating buffers that are too
+   * small to be easily reused.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final int MIN_CACHED_BUFFER_SIZE = 1024;
+
+  /**
+   * Maximum size for a cached buffer. If a larger buffer is required, it will be allocated
+   * but not cached.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
+
+  /**
+   * The fraction of the requested buffer size under which the buffer will be reallocated.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
+
+  /**
+   * Keeping a soft reference to a thread-local buffer. This buffer is used for writing a
+   * {@link ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available.
+   * Using a "soft" reference since VMs may keep this reference around longer than "weak"
+   * (e.g. HotSpot will maintain soft references until memory pressure warrants collection).
+   */
+  private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
+      new ThreadLocal<SoftReference<byte[]>>();
+
+  /**
+   * This is a hack for GAE, where {@code FileOutputStream} is unavailable.
+   */
+  private static final Class<?> FILE_OUTPUT_STREAM_CLASS = safeGetClass("java.io.FileOutputStream");
+  private static final long CHANNEL_FIELD_OFFSET = getChannelFieldOffset(FILE_OUTPUT_STREAM_CLASS);
+
+  /**
+   * For testing purposes only. Clears the cached buffer to force a new allocation on the next
+   * invocation.
+   */
+  static void clearCachedBuffer() {
+    BUFFER.set(null);
+  }
+
+  /**
+   * Writes the remaining content of the buffer to the given stream. The buffer {@code position}
+   * will remain unchanged by this method.
+   */
+  static void write(ByteBuffer buffer, OutputStream output) throws IOException {
+    final int initialPos = buffer.position();
+    try {
+      if (buffer.hasArray()) {
+        // Optimized write for array-backed buffers.
+        // Note that we're taking the risk that a malicious OutputStream could modify the array.
+        output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
+      } else if (!writeToChannel(buffer, output)){
+        // Read all of the data from the buffer to an array.
+        // TODO(nathanmittler): Consider performance improvements for other "known" stream types.
+        final byte[] array = getOrCreateBuffer(buffer.remaining());
+        while (buffer.hasRemaining()) {
+          int length = min(buffer.remaining(), array.length);
+          buffer.get(array, 0, length);
+          output.write(array, 0, length);
+        }
+      }
+    } finally {
+      // Restore the initial position.
+      buffer.position(initialPos);
+    }
+  }
+
+  private static byte[] getOrCreateBuffer(int requestedSize) {
+    requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
+
+    byte[] buffer = getBuffer();
+    // Only allocate if we need to.
+    if (buffer == null || needToReallocate(requestedSize, buffer.length)) {
+      buffer = new byte[requestedSize];
+
+      // Only cache the buffer if it's not too big.
+      if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
+        setBuffer(buffer);
+      }
+    }
+    return buffer;
+  }
+
+  private static boolean needToReallocate(int requestedSize, int bufferLength) {
+    // First check against just the requested length to avoid the multiply.
+    return bufferLength < requestedSize
+        && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
+  }
+
+  private static byte[] getBuffer() {
+    SoftReference<byte[]> sr = BUFFER.get();
+    return sr == null ? null : sr.get();
+  }
+
+  private static void setBuffer(byte[] value) {
+    BUFFER.set(new SoftReference<byte[]>(value));
+  }
+
+  private static boolean writeToChannel(ByteBuffer buffer, OutputStream output) throws IOException {
+    if (CHANNEL_FIELD_OFFSET >= 0 && FILE_OUTPUT_STREAM_CLASS.isInstance(output)) {
+      // Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
+      WritableByteChannel channel = null;
+      try {
+        channel = (WritableByteChannel) UnsafeUtil.getObject(output, CHANNEL_FIELD_OFFSET);
+      } catch (ClassCastException e) {
+        // Absorb.
+      }
+      if (channel != null) {
+        channel.write(buffer);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private static Class<?> safeGetClass(String className) {
+    try {
+      return Class.forName(className);
+    } catch (ClassNotFoundException e) {
+      return null;
+    }
+  }
+  private static long getChannelFieldOffset(Class<?> clazz) {
+    try {
+      if (clazz != null && UnsafeUtil.hasUnsafeArrayOperations()) {
+        Field field = clazz.getDeclaredField("channel");
+        return UnsafeUtil.objectFieldOffset(field);
+      }
+    } catch (Throwable e) {
+      // Absorb
+    }
+    return -1;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteOutput.java b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
new file mode 100644
index 0000000..ee58875
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
@@ -0,0 +1,116 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * An output target for raw bytes. This interface provides semantics that support two types of
+ * writing:
+ *
+ * <p><b>Traditional write operations:</b>
+ * (as defined by {@link java.io.OutputStream}) where the target method is responsible for either
+ * copying the data or completing the write before returning from the method call.
+ *
+ * <p><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
+ * provided buffer and it can therefore be considered immutable. The target method is free to
+ * maintain a reference to the buffer beyond the scope of the method call (e.g. until the write
+ * operation completes).
+ */
+@ExperimentalApi
+public abstract class ByteOutput {
+  /**
+   * Writes a single byte.
+   *
+   * @param value the byte to be written
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(byte value) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+   * not be processed prior to the return of this method call, since {@code value} may be
+   * reused/altered by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written
+   * @param offset the offset of the start of the writable range
+   * @param length the number of bytes to write starting from {@code offset}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(byte[] value, int offset, int length) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+   * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+   * guaranteed not to change by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written
+   * @param offset the offset of the start of the writable range
+   * @param length the number of bytes to write starting from {@code offset}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+   * not be processed prior to the return of this method call, since {@code value} may be
+   * reused/altered by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+   * this buffer will be set to the {@code limit}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(ByteBuffer value) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+   * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+   * guaranteed not to change by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+   * this buffer will be set to the {@code limit}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void writeLazy(ByteBuffer value) throws IOException;
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
index 305236f..d67bb54 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -1,4 +1,32 @@
-// Copyright 2007 Google Inc.  All rights reserved.
+// 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;
 
@@ -15,6 +43,7 @@
 import java.nio.charset.Charset;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -22,14 +51,12 @@
 import java.util.NoSuchElementException;
 
 /**
- * Immutable sequence of bytes.  Substring is supported by sharing the reference
- * to the immutable underlying bytes, as with {@link String}.  Concatenation is
- * likewise supported without copying (long strings) by building a tree of
- * pieces in {@link RopeByteString}.
- * <p>
- * Like {@link String}, the contents of a {@link ByteString} can never be
- * observed to change, not even in the presence of a data race or incorrect
- * API usage in the client code.
+ * Immutable sequence of bytes. Substring is supported by sharing the reference to the immutable
+ * underlying bytes. Concatenation is likewise supported without copying (long strings) by building
+ * a tree of pieces in {@link RopeByteString}.
+ *
+ * <p>Like {@link String}, the contents of a {@link ByteString} can never be observed to change, not
+ * even in the presence of a data race or incorrect API usage in the client code.
  *
  * @author crazybob@google.com Bob Lee
  * @author kenton@google.com Kenton Varda
@@ -60,6 +87,48 @@
   public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
 
   /**
+   * An interface to efficiently copy {@code byte[]}.
+   *
+   * <p>One of the noticeable costs of copying a byte[] into a new array using
+   * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown
+   * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this
+   * expensive nullification and provide substantial performance gain. Unfortunately this does not
+   * hold on Android runtimes and could make the copy slightly slower due to additional code in
+   * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier
+   * for Hotspot and Android runtimes.
+   */
+  private interface ByteArrayCopier {
+    /**
+     * Copies the specified range of the specified array into a new array
+     */
+    byte[] copyFrom(byte[] bytes, int offset, int size);
+  }
+
+  /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */
+  private static final class SystemByteArrayCopier implements ByteArrayCopier {
+    @Override
+    public byte[] copyFrom(byte[] bytes, int offset, int size) {
+      byte[] copy = new byte[size];
+      System.arraycopy(bytes, offset, copy, 0, size);
+      return copy;
+    }
+  }
+
+  /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */
+  private static final class ArraysByteArrayCopier implements ByteArrayCopier {
+    @Override
+    public byte[] copyFrom(byte[] bytes, int offset, int size) {
+      return Arrays.copyOfRange(bytes, offset, offset + size);
+    }
+  }
+
+  private static final ByteArrayCopier byteArrayCopier;
+  static {
+    byteArrayCopier =
+        Android.isOnAndroidDevice() ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
+  }
+
+  /**
    * Cached hash value. Intentionally accessed via a data race, which
    * is safe because of the Java Memory Model's "no out-of-thin-air values"
    * guarantees for ints. A value of 0 implies that the hash has not been set.
@@ -77,7 +146,7 @@
    *
    * @param index index of byte
    * @return the value
-   * @throws ArrayIndexOutOfBoundsException {@code index < 0 or index >= size}
+   * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
    */
   public abstract byte byteAt(int index);
 
@@ -109,7 +178,7 @@
       public byte nextByte() {
         try {
           return byteAt(position++);
-        } catch (ArrayIndexOutOfBoundsException e) {
+        } catch (IndexOutOfBoundsException e) {
           throw new NoSuchElementException(e.getMessage());
         }
       }
@@ -220,9 +289,7 @@
    * @return new {@code ByteString}
    */
   public static ByteString copyFrom(byte[] bytes, int offset, int size) {
-    byte[] copy = new byte[size];
-    System.arraycopy(bytes, offset, copy, 0, size);
-    return new LiteralByteString(copy);
+    return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
   }
 
   /**
@@ -234,7 +301,19 @@
   public static ByteString copyFrom(byte[] bytes) {
     return copyFrom(bytes, 0, bytes.length);
   }
-  
+
+  /**
+   * Wraps the given bytes into a {@code ByteString}. Intended for internal only usage.
+   */
+  static ByteString wrap(ByteBuffer buffer) {
+    if (buffer.hasArray()) {
+      final int offset = buffer.arrayOffset();
+      return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
+    } else {
+      return new NioByteString(buffer);
+    }
+  }
+
   /**
    * Wraps the given bytes into a {@code ByteString}. Intended for internal only
    * usage to force a classload of ByteString before LiteralByteString.
@@ -327,7 +406,7 @@
    * immutable tree of byte arrays ("chunks") of the stream data.  The
    * first chunk is small, with subsequent chunks each being double
    * the size, up to 8K.
-   * 
+   *
    * <p>Each byte read from the input stream will be copied twice to ensure
    * that the resulting ByteString is truly immutable.
    *
@@ -478,7 +557,9 @@
   // Create a balanced concatenation of the next "length" elements from the
   // iterable.
   private static ByteString balancedConcat(Iterator<ByteString> iterator, int length) {
-    assert length >= 1;
+    if (length < 1) {
+      throw new IllegalArgumentException(String.format("length (%s) must be >= 1", length));
+    }
     ByteString result;
     if (length == 1) {
       result = iterator.next();
@@ -559,12 +640,7 @@
   }
 
   /**
-   * Writes the complete contents of this byte string to
-   * the specified output stream argument.
-   *
-   * <p>It is assumed that the {@link OutputStream} will not modify the contents passed it
-   * it. It may be possible for a malicious {@link OutputStream} to corrupt
-   * the data underlying the {@link ByteString}.
+   * Writes a copy of the contents of this byte string to the specified output stream argument.
    *
    * @param  out  the output stream to which to write the data.
    * @throws IOException  if an I/O error occurs.
@@ -578,8 +654,7 @@
    * @param  sourceOffset offset within these bytes
    * @param  numberToWrite number of bytes to write
    * @throws IOException  if an I/O error occurs.
-   * @throws IndexOutOfBoundsException if an offset or size is negative or too
-   *     large
+   * @throws IndexOutOfBoundsException if an offset or size is negative or too large
    */
   final void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
       throws IOException {
@@ -597,6 +672,21 @@
       throws IOException;
 
   /**
+   * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling
+   * this method may result in multiple operations on the target {@link ByteOutput}.
+   *
+   * <p>This method may expose internal backing buffers of the {@link ByteString} to the {@link
+   * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+   * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+   *
+   * @param  byteOutput  the output target to receive the bytes
+   * @throws IOException  if an I/O error occurs
+   * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput)
+   */
+  abstract void writeTo(ByteOutput byteOutput) throws IOException;
+
+
+  /**
    * Constructs a read-only {@code java.nio.ByteBuffer} whose content
    * is equal to the contents of this byte string.
    * The result uses the same backing array as the byte string, if possible.
@@ -737,6 +827,7 @@
       return true;
     }
 
+
     /**
      * Check equality of the substring of given length of this object starting at
      * zero with another {@code ByteString} substring starting at offset.
@@ -1102,7 +1193,7 @@
    *
    * @param index the index position to be tested
    * @param size the length of the array
-   * @throws ArrayIndexOutOfBoundsException if the index does not fall within the array.
+   * @throws IndexOutOfBoundsException if the index does not fall within the array.
    */
   static void checkIndex(int index, int size) {
     if ((index | (size - (index + 1))) < 0) {
@@ -1120,7 +1211,7 @@
    * @param endIndex the end index of the range (exclusive)
    * @param size the size of the array.
    * @return the length of the range.
-   * @throws ArrayIndexOutOfBoundsException some or all of the range falls outside of the array.
+   * @throws IndexOutOfBoundsException some or all of the range falls outside of the array.
    */
   static int checkRange(int startIndex, int endIndex, int size) {
     final int length = endIndex - startIndex;
@@ -1143,7 +1234,7 @@
     return String.format("<ByteString@%s size=%d>",
         Integer.toHexString(System.identityHashCode(this)), size());
   }
-  
+
   /**
    * This class implements a {@link com.google.protobuf.ByteString} backed by a
    * single array of bytes, contiguous in memory. It supports substring by
@@ -1236,6 +1327,11 @@
     }
 
     @Override
+    final void writeTo(ByteOutput output) throws IOException {
+      output.writeLazy(bytes, getOffsetIntoBytes(), size());
+    }
+
+    @Override
     protected final String toStringInternal(Charset charset) {
       return new String(bytes, getOffsetIntoBytes(), size(), charset);
     }
@@ -1362,7 +1458,7 @@
       return 0;
     }
   }
-  
+
   /**
    * This class is used to represent the substring of a {@link ByteString} over a
    * single byte array. In terms of the public API of {@link ByteString}, you end
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 b3118ee..1297462 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -30,55 +30,119 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.Internal.EMPTY_BYTE_ARRAY;
+import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER;
+import static com.google.protobuf.Internal.UTF_8;
+import static com.google.protobuf.Internal.checkNotNull;
+import static com.google.protobuf.WireFormat.FIXED32_SIZE;
+import static com.google.protobuf.WireFormat.FIXED64_SIZE;
+import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
 /**
  * Reads and decodes protocol message fields.
  *
- * This class contains two kinds of methods:  methods that read specific
- * protocol message constructs and field types (e.g. {@link #readTag()} and
- * {@link #readInt32()}) and methods that read low-level values (e.g.
- * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
- * encoded protocol messages, you should use the former methods, but if you are
- * reading some other format of your own design, use the latter.
+ * <p>This class contains two kinds of methods: methods that read specific protocol message
+ * constructs and field types (e.g. {@link #readTag()} and {@link #readInt32()}) and methods that
+ * read low-level values (e.g. {@link #readRawVarint32()} and {@link #readRawBytes}). If you are
+ * reading encoded protocol messages, you should use the former methods, but if you are reading some
+ * other format of your own design, use the latter.
  *
  * @author kenton@google.com Kenton Varda
  */
-public final class CodedInputStream {
-  /**
-   * Create a new CodedInputStream wrapping the given InputStream.
-   */
-  public static CodedInputStream newInstance(final InputStream input) {
-    return new CodedInputStream(input);
-  }
+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;
 
   /**
-   * Create a new CodedInputStream wrapping the given byte array.
+   * Whether to enable our custom UTF-8 decode codepath which does not use {@link StringCoding}.
+   * Currently disabled.
    */
+  private static final boolean ENABLE_CUSTOM_UTF8_DECODE = false;
+
+  /** Visible for subclasses. See setRecursionLimit() */
+  int recursionDepth;
+
+  int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+  /** Visible for subclasses. See setSizeLimit() */
+  int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+  /** Create a new CodedInputStream wrapping the given InputStream. */
+  public static CodedInputStream newInstance(final InputStream input) {
+    return newInstance(input, DEFAULT_BUFFER_SIZE);
+  }
+
+  /** Create a new CodedInputStream wrapping the given InputStream. */
+  static CodedInputStream newInstance(final InputStream input, int bufferSize) {
+    if (input == null) {
+      // TODO(nathanmittler): Ideally we should throw here. This is done for backward compatibility.
+      return newInstance(EMPTY_BYTE_ARRAY);
+    }
+    return new StreamDecoder(input, bufferSize);
+  }
+
+  /** Create a new CodedInputStream wrapping the given {@code Iterable <ByteBuffer>}. */
+  public static CodedInputStream newInstance(final Iterable<ByteBuffer> input) {
+    if (!UnsafeDirectNioDecoder.isSupported()) {
+      return newInstance(new IterableByteBufferInputStream(input));
+    }
+    return newInstance(input, false);
+  }
+
+  /** Create a new CodedInputStream wrapping the given {@code Iterable <ByteBuffer>}. */
+  static CodedInputStream newInstance(
+      final Iterable<ByteBuffer> bufs, final boolean bufferIsImmutable) {
+    // flag is to check the type of input's ByteBuffers.
+    // flag equals 1: all ByteBuffers have array.
+    // flag equals 2: all ByteBuffers are direct ByteBuffers.
+    // flag equals 3: some ByteBuffers are direct and some have array.
+    // flag greater than 3: other cases.
+    int flag = 0;
+    // Total size of the input
+    int totalSize = 0;
+    for (ByteBuffer buf : bufs) {
+      totalSize += buf.remaining();
+      if (buf.hasArray()) {
+        flag |= 1;
+      } else if (buf.isDirect()) {
+        flag |= 2;
+      } else {
+        flag |= 4;
+      }
+    }
+    if (flag == 2) {
+      return new IterableDirectByteBufferDecoder(bufs, totalSize, bufferIsImmutable);
+    } else {
+      // TODO(yilunchong): add another decoders to deal case 1 and 3.
+      return newInstance(new IterableByteBufferInputStream(bufs));
+    }
+  }
+
+  /** Create a new CodedInputStream wrapping the given byte array. */
   public static CodedInputStream newInstance(final byte[] buf) {
     return newInstance(buf, 0, buf.length);
   }
 
-  /**
-   * Create a new CodedInputStream wrapping the given byte array slice.
-   */
-  public static CodedInputStream newInstance(final byte[] buf, final int off,
-                                             final int len) {
-    return newInstance(buf, off, len, false);
+  /** Create a new CodedInputStream wrapping the given byte array slice. */
+  public static CodedInputStream newInstance(final byte[] buf, final int off, final int len) {
+    return newInstance(buf, off, len, false /* bufferIsImmutable */);
   }
 
-  /**
-   * Create a new CodedInputStream wrapping the given byte array slice.
-   */
-  public static CodedInputStream newInstance(final byte[] buf, final int off,
-                                             final int len, boolean bufferIsImmutable) {
-    CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable);
+  /** Create a new CodedInputStream wrapping the given byte array slice. */
+  static CodedInputStream newInstance(
+      final byte[] buf, final int off, final int len, final boolean bufferIsImmutable) {
+    ArrayDecoder result = new ArrayDecoder(buf, off, len, bufferIsImmutable);
     try {
       // Some uses of CodedInputStream can be more efficient if they know
       // exactly how many bytes are available.  By pushing the end point of the
@@ -100,571 +164,415 @@
   }
 
   /**
-   * Create a new CodedInputStream wrapping the given ByteBuffer. The data
-   * starting from the ByteBuffer's current position to its limit will be read.
-   * The returned CodedInputStream may or may not share the underlying data
-   * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the
-   * CodedInputStream is in use.
-   * Note that the ByteBuffer's position won't be changed by this function.
-   * Concurrent calls with the same ByteBuffer object are safe if no other
-   * thread is trying to alter the ByteBuffer's status.
+   * Create a new CodedInputStream wrapping the given ByteBuffer. The data starting from the
+   * ByteBuffer's current position to its limit will be read. The returned CodedInputStream may or
+   * may not share the underlying data in the ByteBuffer, therefore the ByteBuffer cannot be changed
+   * while the CodedInputStream is in use. Note that the ByteBuffer's position won't be changed by
+   * this function. Concurrent calls with the same ByteBuffer object are safe if no other thread is
+   * trying to alter the ByteBuffer's status.
    */
   public static CodedInputStream newInstance(ByteBuffer buf) {
-    if (buf.hasArray()) {
-      return newInstance(buf.array(), buf.arrayOffset() + buf.position(),
-          buf.remaining());
-    } else {
-      ByteBuffer temp = buf.duplicate();
-      byte[] buffer = new byte[temp.remaining()];
-      temp.get(buffer);
-      return newInstance(buffer);
-    }
+    return newInstance(buf, false /* bufferIsImmutable */);
   }
 
+  /** Create a new CodedInputStream wrapping the given buffer. */
+  static CodedInputStream newInstance(ByteBuffer buf, boolean bufferIsImmutable) {
+    if (buf.hasArray()) {
+      return newInstance(
+          buf.array(), buf.arrayOffset() + buf.position(), buf.remaining(), bufferIsImmutable);
+    }
+
+    if (buf.isDirect() && UnsafeDirectNioDecoder.isSupported()) {
+      return new UnsafeDirectNioDecoder(buf, bufferIsImmutable);
+    }
+
+    // The buffer is non-direct and does not expose the underlying array. Using the ByteBuffer API
+    // to access individual bytes is very slow, so just copy the buffer to an array.
+    // TODO(nathanmittler): Re-evaluate with Java 9
+    byte[] buffer = new byte[buf.remaining()];
+    buf.duplicate().get(buffer);
+    return newInstance(buffer, 0, buffer.length, true);
+  }
+
+  /** Disable construction/inheritance outside of this class. */
+  private CodedInputStream() {}
+
   // -----------------------------------------------------------------
 
   /**
-   * Attempt to read a field tag, returning zero if we have reached EOF.
-   * Protocol message parsers use this to read tags, since a protocol message
-   * may legally end wherever a tag occurs, and zero is not a valid tag number.
+   * Attempt to read a field tag, returning zero if we have reached EOF. Protocol message parsers
+   * use this to read tags, since a protocol message may legally end wherever a tag occurs, and zero
+   * is not a valid tag number.
    */
-  public int readTag() throws IOException {
-    if (isAtEnd()) {
-      lastTag = 0;
-      return 0;
-    }
-
-    lastTag = readRawVarint32();
-    if (WireFormat.getTagFieldNumber(lastTag) == 0) {
-      // If we actually read zero (or any tag number corresponding to field
-      // number zero), that's not a valid tag.
-      throw InvalidProtocolBufferException.invalidTag();
-    }
-    return lastTag;
-  }
+  public abstract int readTag() throws IOException;
 
   /**
-   * Verifies that the last call to readTag() returned the given tag value.
-   * This is used to verify that a nested group ended with the correct
-   * end tag.
+   * Verifies that the last call to readTag() returned the given tag value. This is used to verify
+   * that a nested group ended with the correct end tag.
    *
-   * @throws InvalidProtocolBufferException {@code value} does not match the
-   *                                        last tag.
+   * @throws InvalidProtocolBufferException {@code value} does not match the last tag.
    */
-  public void checkLastTagWas(final int value)
-                              throws InvalidProtocolBufferException {
-    if (lastTag != value) {
-      throw InvalidProtocolBufferException.invalidEndTag();
-    }
-  }
+  public abstract void checkLastTagWas(final int value) throws InvalidProtocolBufferException;
 
-  public int getLastTag() {
-    return lastTag;
-  }
+  public abstract int getLastTag();
 
   /**
    * Reads and discards a single field, given its tag value.
    *
-   * @return {@code false} if the tag is an endgroup tag, in which case
-   *         nothing is skipped.  Otherwise, returns {@code true}.
+   * @return {@code false} if the tag is an endgroup tag, in which case nothing is skipped.
+   *     Otherwise, returns {@code true}.
    */
-  public boolean skipField(final int tag) throws IOException {
-    switch (WireFormat.getTagWireType(tag)) {
-      case WireFormat.WIRETYPE_VARINT:
-        skipRawVarint();
-        return true;
-      case WireFormat.WIRETYPE_FIXED64:
-        skipRawBytes(8);
-        return true;
-      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-        skipRawBytes(readRawVarint32());
-        return true;
-      case WireFormat.WIRETYPE_START_GROUP:
-        skipMessage();
-        checkLastTagWas(
-          WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
-                             WireFormat.WIRETYPE_END_GROUP));
-        return true;
-      case WireFormat.WIRETYPE_END_GROUP:
-        return false;
-      case WireFormat.WIRETYPE_FIXED32:
-        skipRawBytes(4);
-        return true;
-      default:
-        throw InvalidProtocolBufferException.invalidWireType();
-    }
-  }
+  public abstract boolean skipField(final int tag) throws IOException;
 
   /**
-   * Reads a single field and writes it to output in wire format,
-   * given its tag value.
+   * Reads a single field and writes it to output in wire format, given its tag value.
    *
-   * @return {@code false} if the tag is an endgroup tag, in which case
-   *         nothing is skipped.  Otherwise, returns {@code true}.
+   * @return {@code false} if the tag is an endgroup tag, in which case nothing is skipped.
+   *     Otherwise, returns {@code true}.
+   * @deprecated use {@code UnknownFieldSet} or {@code UnknownFieldSetLite} to skip to an output
+   *     stream.
    */
-  public boolean skipField(final int tag, final CodedOutputStream output)
-      throws IOException {
-    switch (WireFormat.getTagWireType(tag)) {
-      case WireFormat.WIRETYPE_VARINT: {
-        long value = readInt64();
-        output.writeRawVarint32(tag);
-        output.writeUInt64NoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_FIXED64: {
-        long value = readRawLittleEndian64();
-        output.writeRawVarint32(tag);
-        output.writeFixed64NoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_LENGTH_DELIMITED: {
-        ByteString value = readBytes();
-        output.writeRawVarint32(tag);
-        output.writeBytesNoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_START_GROUP: {
-        output.writeRawVarint32(tag);
-        skipMessage(output);
-        int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
-                                        WireFormat.WIRETYPE_END_GROUP);
-        checkLastTagWas(endtag);
-        output.writeRawVarint32(endtag);
-        return true;
-      }
-      case WireFormat.WIRETYPE_END_GROUP: {
-        return false;
-      }
-      case WireFormat.WIRETYPE_FIXED32: {
-        int value = readRawLittleEndian32();
-        output.writeRawVarint32(tag);
-        output.writeFixed32NoTag(value);
-        return true;
-      }
-      default:
-        throw InvalidProtocolBufferException.invalidWireType();
-    }
-  }
+  @Deprecated
+  public abstract boolean skipField(final int tag, final CodedOutputStream output)
+      throws IOException;
 
   /**
-   * Reads and discards an entire message.  This will read either until EOF
-   * or until an endgroup tag, whichever comes first.
-   */
-  public void skipMessage() throws IOException {
-    while (true) {
-      final int tag = readTag();
-      if (tag == 0 || !skipField(tag)) {
-        return;
-      }
-    }
-  }
-
-  /**
-   * Reads an entire message and writes it to output in wire format.
-   * This will read either until EOF or until an endgroup tag,
+   * Reads and discards an entire message. This will read either until EOF or until an endgroup tag,
    * whichever comes first.
    */
-  public void skipMessage(CodedOutputStream output) throws IOException {
-    while (true) {
-      final int tag = readTag();
-      if (tag == 0 || !skipField(tag, output)) {
-        return;
-      }
-    }
-  }
+  public abstract void skipMessage() throws IOException;
 
   /**
-   * Collects the bytes skipped and returns the data in a ByteBuffer.
+   * Reads an entire message and writes it to output in wire format. This will read either until EOF
+   * or until an endgroup tag, whichever comes first.
    */
-  private class SkippedDataSink implements RefillCallback {
-    private int lastPos = bufferPos;
-    private ByteArrayOutputStream byteArrayStream;
-
-    @Override
-    public void onRefill() {
-      if (byteArrayStream == null) {
-        byteArrayStream = new ByteArrayOutputStream();
-      }
-      byteArrayStream.write(buffer, lastPos, bufferPos - lastPos);
-      lastPos = 0;
-    }
-
-    /**
-     * Gets skipped data in a ByteBuffer. This method should only be
-     * called once.
-     */
-    ByteBuffer getSkippedData() {
-      if (byteArrayStream == null) {
-        return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos);
-      } else {
-        byteArrayStream.write(buffer, lastPos, bufferPos);
-        return ByteBuffer.wrap(byteArrayStream.toByteArray());
-      }
-    }
-  }
+  public abstract void skipMessage(CodedOutputStream output) throws IOException;
 
 
   // -----------------------------------------------------------------
 
   /** Read a {@code double} field value from the stream. */
-  public double readDouble() throws IOException {
-    return Double.longBitsToDouble(readRawLittleEndian64());
-  }
+  public abstract double readDouble() throws IOException;
 
   /** Read a {@code float} field value from the stream. */
-  public float readFloat() throws IOException {
-    return Float.intBitsToFloat(readRawLittleEndian32());
-  }
+  public abstract float readFloat() throws IOException;
 
   /** Read a {@code uint64} field value from the stream. */
-  public long readUInt64() throws IOException {
-    return readRawVarint64();
-  }
+  public abstract long readUInt64() throws IOException;
 
   /** Read an {@code int64} field value from the stream. */
-  public long readInt64() throws IOException {
-    return readRawVarint64();
-  }
+  public abstract long readInt64() throws IOException;
 
   /** Read an {@code int32} field value from the stream. */
-  public int readInt32() throws IOException {
-    return readRawVarint32();
-  }
+  public abstract int readInt32() throws IOException;
 
   /** Read a {@code fixed64} field value from the stream. */
-  public long readFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
+  public abstract long readFixed64() throws IOException;
 
   /** Read a {@code fixed32} field value from the stream. */
-  public int readFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
+  public abstract int readFixed32() throws IOException;
 
   /** Read a {@code bool} field value from the stream. */
-  public boolean readBool() throws IOException {
-    return readRawVarint64() != 0;
-  }
+  public abstract boolean readBool() throws IOException;
 
   /**
-   * Read a {@code string} field value from the stream.
-   * If the stream contains malformed UTF-8,
+   * Read a {@code string} field value from the stream. If the stream contains malformed UTF-8,
    * replace the offending bytes with the standard UTF-8 replacement character.
    */
-  public String readString() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      final String result = new String(buffer, bufferPos, size, Internal.UTF_8);
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return "";
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      return new String(readRawBytesSlowPath(size), Internal.UTF_8);
-    }
-  }
+  public abstract String readString() throws IOException;
 
   /**
-   * Read a {@code string} field value from the stream.
-   * If the stream contains malformed UTF-8,
+   * Read a {@code string} field value from the stream. If the stream contains malformed UTF-8,
    * throw exception {@link InvalidProtocolBufferException}.
    */
-  public String readStringRequireUtf8() throws IOException {
-    final int size = readRawVarint32();
-    final byte[] bytes;
-    int pos = bufferPos;
-    if (size <= (bufferSize - pos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      bytes = buffer;
-      bufferPos = pos + size;
-    } else if (size == 0) {
-      return "";
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      bytes = readRawBytesSlowPath(size);
-      pos = 0;
-    }
-    // TODO(martinrb): We could save a pass by validating while decoding.
-    if (!Utf8.isValidUtf8(bytes, pos, pos + size)) {
-      throw InvalidProtocolBufferException.invalidUtf8();
-    }
-    return new String(bytes, pos, size, Internal.UTF_8);
-  }
+  public abstract String readStringRequireUtf8() throws IOException;
 
   /** Read a {@code group} field value from the stream. */
-  public void readGroup(final int fieldNumber,
-                        final MessageLite.Builder builder,
-                        final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    builder.mergeFrom(this, extensionRegistry);
-    checkLastTagWas(
-      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-    --recursionDepth;
-  }
-
-
-  /** Read a {@code group} field value from the stream. */
-  public <T extends MessageLite> T readGroup(
+  public abstract void readGroup(
       final int fieldNumber,
-      final Parser<T> parser,
+      final MessageLite.Builder builder,
       final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    T result = parser.parsePartialFrom(this, extensionRegistry);
-    checkLastTagWas(
-      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-    --recursionDepth;
-    return result;
-  }
+      throws IOException;
+
+
+  /** Read a {@code group} field value from the stream. */
+  public abstract <T extends MessageLite> T readGroup(
+      final int fieldNumber, final Parser<T> parser, final ExtensionRegistryLite extensionRegistry)
+      throws IOException;
 
   /**
-   * Reads a {@code group} field value from the stream and merges it into the
-   * given {@link UnknownFieldSet}.
+   * Reads a {@code group} field value from the stream and merges it into the given {@link
+   * UnknownFieldSet}.
    *
-   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
-   *             you can just call {@link #readGroup}.
+   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so you can just call
+   *     {@link #readGroup}.
    */
   @Deprecated
-  public void readUnknownGroup(final int fieldNumber,
-                               final MessageLite.Builder builder)
-      throws IOException {
-    // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
-    // is safe to pass null here.  (We can't call
-    // ExtensionRegistry.getEmptyRegistry() because that would make this
-    // class depend on ExtensionRegistry, which is not part of the lite
-    // library.)
-    readGroup(fieldNumber, builder, null);
-  }
+  public abstract void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+      throws IOException;
 
   /** Read an embedded message field value from the stream. */
-  public void readMessage(final MessageLite.Builder builder,
-                          final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    final int length = readRawVarint32();
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    final int oldLimit = pushLimit(length);
-    ++recursionDepth;
-    builder.mergeFrom(this, extensionRegistry);
-    checkLastTagWas(0);
-    --recursionDepth;
-    popLimit(oldLimit);
-  }
+  public abstract void readMessage(
+      final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+      throws IOException;
 
 
   /** Read an embedded message field value from the stream. */
-  public <T extends MessageLite> T readMessage(
-      final Parser<T> parser,
-      final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    int length = readRawVarint32();
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    final int oldLimit = pushLimit(length);
-    ++recursionDepth;
-    T result = parser.parsePartialFrom(this, extensionRegistry);
-    checkLastTagWas(0);
-    --recursionDepth;
-    popLimit(oldLimit);
-    return result;
-  }
+  public abstract <T extends MessageLite> T readMessage(
+      final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException;
 
   /** Read a {@code bytes} field value from the stream. */
-  public ByteString readBytes() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      final ByteString result = bufferIsImmutable && enableAliasing
-          ? ByteString.wrap(buffer, bufferPos, size)
-          : ByteString.copyFrom(buffer, bufferPos, size);
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return ByteString.EMPTY;
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      return ByteString.wrap(readRawBytesSlowPath(size));
-    }
-  }
+  public abstract ByteString readBytes() throws IOException;
 
   /** Read a {@code bytes} field value from the stream. */
-  public byte[] readByteArray() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path: We already have the bytes in a contiguous buffer, so
-      // just copy directly from it.
-      final byte[] result =
-          Arrays.copyOfRange(buffer, bufferPos, bufferPos + size);
-      bufferPos += size;
-      return result;
-    } else {
-      // Slow path: Build a byte array first then copy it.
-      return readRawBytesSlowPath(size);
-    }
-  }
+  public abstract byte[] readByteArray() throws IOException;
 
   /** Read a {@code bytes} field value from the stream. */
-  public ByteBuffer readByteBuffer() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path: We already have the bytes in a contiguous buffer.
-      // When aliasing is enabled, we can return a ByteBuffer pointing directly
-      // into the underlying byte array without copy if the CodedInputStream is
-      // constructed from a byte array. If aliasing is disabled or the input is
-      // from an InputStream or ByteString, we have to make a copy of the bytes.
-      ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing
-          ? ByteBuffer.wrap(buffer, bufferPos, size).slice()
-          : ByteBuffer.wrap(Arrays.copyOfRange(
-              buffer, bufferPos, bufferPos + size));
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return Internal.EMPTY_BYTE_BUFFER;
-    } else {
-      // Slow path: Build a byte array first then copy it.
-      return ByteBuffer.wrap(readRawBytesSlowPath(size));
-    }
-  }
+  public abstract ByteBuffer readByteBuffer() throws IOException;
 
   /** Read a {@code uint32} field value from the stream. */
-  public int readUInt32() throws IOException {
-    return readRawVarint32();
-  }
+  public abstract int readUInt32() throws IOException;
 
   /**
-   * Read an enum field value from the stream.  Caller is responsible
-   * for converting the numeric value to an actual enum.
+   * Read an enum field value from the stream. Caller is responsible for converting the numeric
+   * value to an actual enum.
    */
-  public int readEnum() throws IOException {
-    return readRawVarint32();
-  }
+  public abstract int readEnum() throws IOException;
 
   /** Read an {@code sfixed32} field value from the stream. */
-  public int readSFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
+  public abstract int readSFixed32() throws IOException;
 
   /** Read an {@code sfixed64} field value from the stream. */
-  public long readSFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
+  public abstract long readSFixed64() throws IOException;
 
   /** Read an {@code sint32} field value from the stream. */
-  public int readSInt32() throws IOException {
-    return decodeZigZag32(readRawVarint32());
-  }
+  public abstract int readSInt32() throws IOException;
 
   /** Read an {@code sint64} field value from the stream. */
-  public long readSInt64() throws IOException {
-    return decodeZigZag64(readRawVarint64());
-  }
+  public abstract long readSInt64() throws IOException;
 
   // =================================================================
 
+  /** Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits. */
+  public abstract int readRawVarint32() throws IOException;
+
+  /** Read a raw Varint from the stream. */
+  public abstract long readRawVarint64() throws IOException;
+
+  /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
+  /* Visible for testing */
+  abstract long readRawVarint64SlowPath() throws IOException;
+
+  /** Read a 32-bit little-endian integer from the stream. */
+  public abstract int readRawLittleEndian32() throws IOException;
+
+  /** Read a 64-bit little-endian integer from the stream. */
+  public abstract long readRawLittleEndian64() throws IOException;
+
+  // -----------------------------------------------------------------
+
   /**
-   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
-   * upper bits.
+   * Enables {@link ByteString} aliasing of the underlying buffer, trading off on buffer pinning for
+   * data copies. Only valid for buffer-backed streams.
    */
-  public int readRawVarint32() throws IOException {
-    // See implementation notes for readRawVarint64
- fastpath: {
-      int pos = bufferPos;
+  public abstract void enableAliasing(boolean enabled);
 
-      if (bufferSize == pos) {
-        break fastpath;
-      }
-
-      final byte[] buffer = this.buffer;
-      int x;
-      if ((x = buffer[pos++]) >= 0) {
-        bufferPos = pos;
-        return x;
-      } else if (bufferSize - pos < 9) {
-        break fastpath;
-      } else if ((x ^= (buffer[pos++] << 7)) < 0) {
-        x ^= (~0 << 7);
-      } else if ((x ^= (buffer[pos++] << 14)) >= 0) {
-        x ^= (~0 << 7) ^ (~0 << 14);
-      } else if ((x ^= (buffer[pos++] << 21)) < 0) {
-        x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
-      } else {
-        int y = buffer[pos++];
-        x ^= y << 28;
-        x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
-        if (y < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0) {
-          break fastpath;  // Will throw malformedVarint()
-        }
-      }
-      bufferPos = pos;
-      return x;
+  /**
+   * Set the maximum message recursion depth. In order to prevent malicious messages from causing
+   * stack overflows, {@code CodedInputStream} limits how deeply messages may be nested. The default
+   * limit is 64.
+   *
+   * @return the old limit.
+   */
+  public final int setRecursionLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException("Recursion limit cannot be negative: " + limit);
     }
-    return (int) readRawVarint64SlowPath();
-  }
-
-  private void skipRawVarint() throws IOException {
-    if (bufferSize - bufferPos >= 10) {
-      final byte[] buffer = this.buffer;
-      int pos = bufferPos;
-      for (int i = 0; i < 10; i++) {
-        if (buffer[pos++] >= 0) {
-          bufferPos = pos;
-          return;
-        }
-      }
-    }
-    skipRawVarintSlowPath();
-  }
-
-  private void skipRawVarintSlowPath() throws IOException {
-    for (int i = 0; i < 10; i++) {
-      if (readRawByte() >= 0) {
-        return;
-      }
-    }
-    throw InvalidProtocolBufferException.malformedVarint();
+    final int oldLimit = recursionLimit;
+    recursionLimit = limit;
+    return oldLimit;
   }
 
   /**
-   * Reads a varint from the input one byte at a time, so that it does not
-   * read any bytes after the end of the varint.  If you simply wrapped the
-   * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
-   * then you would probably end up reading past the end of the varint since
-   * CodedInputStream buffers its input.
+   * Only valid for {@link InputStream}-backed streams.
+   *
+   * <p>Set the maximum message size. In order to prevent malicious messages from exhausting memory
+   * or causing integer overflows, {@code CodedInputStream} limits how large a message may be. The
+   * default limit is {@code Integer.MAX_INT}. You should set this limit as small as you can without
+   * harming your app's functionality. Note that size limits only apply when reading from an {@code
+   * InputStream}, not when constructed around a raw byte array.
+   *
+   * <p>If you want to read several messages from a single CodedInputStream, you could call {@link
+   * #resetSizeCounter()} after each one to avoid hitting the size limit.
+   *
+   * @return the old limit.
    */
-  static int readRawVarint32(final InputStream input) throws IOException {
-    final int firstByte = input.read();
-    if (firstByte == -1) {
-      throw InvalidProtocolBufferException.truncatedMessage();
+  public final int setSizeLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException("Size limit cannot be negative: " + limit);
     }
-    return readRawVarint32(firstByte, input);
+    final int oldLimit = sizeLimit;
+    sizeLimit = limit;
+    return oldLimit;
+  }
+
+
+  private boolean explicitDiscardUnknownFields = false;
+
+  private static volatile boolean proto3DiscardUnknownFieldsDefault = false;
+
+  static void setProto3DiscardUnknownsByDefaultForTest() {
+    proto3DiscardUnknownFieldsDefault = true;
+  }
+
+  static void setProto3KeepUnknownsByDefaultForTest() {
+    proto3DiscardUnknownFieldsDefault = false;
+  }
+
+  static boolean getProto3DiscardUnknownFieldsDefault() {
+    return proto3DiscardUnknownFieldsDefault;
   }
 
   /**
-   * Like {@link #readRawVarint32(InputStream)}, but expects that the caller
-   * has already read one byte.  This allows the caller to determine if EOF
-   * has been reached before attempting to read.
+   * Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime
+   * messages; lite messages will always preserve unknowns.
+   *
+   * <p>Note calling this function alone will have NO immediate effect on the underlying input data.
+   * The unknown fields will be discarded during parsing. This affects both Proto2 and Proto3 full
+   * runtime.
    */
-  public static int readRawVarint32(
-      final int firstByte, final InputStream input) throws IOException {
+  final void discardUnknownFields() {
+    explicitDiscardUnknownFields = true;
+  }
+
+  /**
+   * Reverts the unknown fields preservation behavior for Proto2 and Proto3 full runtime to their
+   * default.
+   */
+  final void unsetDiscardUnknownFields() {
+    explicitDiscardUnknownFields = false;
+  }
+
+  /**
+   * Whether unknown fields in this input stream should be discarded during parsing into full
+   * runtime messages.
+   */
+  final boolean shouldDiscardUnknownFields() {
+    return explicitDiscardUnknownFields;
+  }
+
+  /**
+   * Whether unknown fields in this input stream should be discarded during parsing for proto3 full
+   * runtime messages.
+   *
+   * <p>This function was temporarily introduced before proto3 unknown fields behavior is changed.
+   * TODO(liujisi): remove this and related code in GeneratedMessage after proto3 unknown
+   * fields migration is done.
+   */
+  final boolean shouldDiscardUnknownFieldsProto3() {
+    return explicitDiscardUnknownFields ? true : proto3DiscardUnknownFieldsDefault;
+  }
+
+  /**
+   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). Only valid for {@link
+   * InputStream}-backed streams.
+   */
+  public abstract void resetSizeCounter();
+
+  /**
+   * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This is called when
+   * descending into a length-delimited embedded message.
+   *
+   * <p>Note that {@code pushLimit()} does NOT affect how many bytes the {@code CodedInputStream}
+   * reads from an underlying {@code InputStream} when refreshing its buffer. If you need to prevent
+   * reading past a certain point in the underlying {@code InputStream} (e.g. because you expect it
+   * to contain more data after the end of the message which you need to handle differently) then
+   * you must place a wrapper around your {@code InputStream} which limits the amount of data that
+   * can be read from it.
+   *
+   * @return the old limit.
+   */
+  public abstract int pushLimit(int byteLimit) throws InvalidProtocolBufferException;
+
+  /**
+   * Discards the current limit, returning to the previous limit.
+   *
+   * @param oldLimit The old limit, as returned by {@code pushLimit}.
+   */
+  public abstract void popLimit(final int oldLimit);
+
+  /**
+   * Returns the number of bytes to be read before the current limit. If no limit is set, returns
+   * -1.
+   */
+  public abstract int getBytesUntilLimit();
+
+  /**
+   * Returns true if the stream has reached the end of the input. This is the case if either the end
+   * of the underlying input source has been reached or if the stream has reached a limit created
+   * using {@link #pushLimit(int)}.
+   */
+  public abstract boolean isAtEnd() throws IOException;
+
+  /**
+   * The total bytes read up to the current position. Calling {@link #resetSizeCounter()} resets
+   * this value to zero.
+   */
+  public abstract int getTotalBytesRead();
+
+  /**
+   * Read one byte from the input.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current limit was reached.
+   */
+  public abstract byte readRawByte() throws IOException;
+
+  /**
+   * Read a fixed size of bytes from the input.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current limit was reached.
+   */
+  public abstract byte[] readRawBytes(final int size) throws IOException;
+
+  /**
+   * Reads and discards {@code size} bytes.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current limit was reached.
+   */
+  public abstract void skipRawBytes(final int size) throws IOException;
+
+  /**
+   * Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into values that can be
+   * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits
+   * to be varint encoded, thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 32-bit integer, stored in a signed int because Java has no explicit
+   *     unsigned support.
+   * @return A signed 32-bit integer.
+   */
+  public static int decodeZigZag32(final int n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be
+   * efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits
+   * to be varint encoded, thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 64-bit integer, stored in a signed int because Java has no explicit
+   *     unsigned support.
+   * @return A signed 64-bit integer.
+   */
+  public static long decodeZigZag64(final long n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  /**
+   * Like {@link #readRawVarint32(InputStream)}, but expects that the caller has already read one
+   * byte. This allows the caller to determine if EOF has been reached before attempting to read.
+   */
+  public static int readRawVarint32(final int firstByte, final InputStream input)
+      throws IOException {
     if ((firstByte & 0x80) == 0) {
       return firstByte;
     }
@@ -694,589 +602,3341 @@
     throw InvalidProtocolBufferException.malformedVarint();
   }
 
-  /** Read a raw Varint from the stream. */
-  public long readRawVarint64() throws IOException {
-    // Implementation notes:
-    //
-    // Optimized for one-byte values, expected to be common.
-    // The particular code below was selected from various candidates
-    // empirically, by winning VarintBenchmark.
-    //
-    // Sign extension of (signed) Java bytes is usually a nuisance, but
-    // we exploit it here to more easily obtain the sign of bytes read.
-    // Instead of cleaning up the sign extension bits by masking eagerly,
-    // we delay until we find the final (positive) byte, when we clear all
-    // accumulated bits with one xor.  We depend on javac to constant fold.
- fastpath: {
-      int pos = bufferPos;
+  /**
+   * Reads a varint from the input one byte at a time, so that it does not read any bytes after the
+   * end of the varint. If you simply wrapped the stream in a CodedInputStream and used {@link
+   * #readRawVarint32(InputStream)} then you would probably end up reading past the end of the
+   * varint since CodedInputStream buffers its input.
+   */
+  static int readRawVarint32(final InputStream input) throws IOException {
+    final int firstByte = input.read();
+    if (firstByte == -1) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+    return readRawVarint32(firstByte, input);
+  }
 
-      if (bufferSize == pos) {
-        break fastpath;
+  /** A {@link CodedInputStream} implementation that uses a backing array as the input. */
+  private static final class ArrayDecoder extends CodedInputStream {
+    private final byte[] buffer;
+    private final boolean immutable;
+    private int limit;
+    private int bufferSizeAfterLimit;
+    private int pos;
+    private int startPos;
+    private int lastTag;
+    private boolean enableAliasing;
+
+    /** The absolute position of the end of the current message. */
+    private int currentLimit = Integer.MAX_VALUE;
+
+    private ArrayDecoder(final byte[] buffer, final int offset, final int len, boolean immutable) {
+      this.buffer = buffer;
+      limit = offset + len;
+      pos = offset;
+      startPos = pos;
+      this.immutable = immutable;
+    }
+
+    @Override
+    public int readTag() throws IOException {
+      if (isAtEnd()) {
+        lastTag = 0;
+        return 0;
+      }
+
+      lastTag = readRawVarint32();
+      if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+        // If we actually read zero (or any tag number corresponding to field
+        // number zero), that's not a valid tag.
+        throw InvalidProtocolBufferException.invalidTag();
+      }
+      return lastTag;
+    }
+
+    @Override
+    public void checkLastTagWas(final int value) throws InvalidProtocolBufferException {
+      if (lastTag != value) {
+        throw InvalidProtocolBufferException.invalidEndTag();
+      }
+    }
+
+    @Override
+    public int getLastTag() {
+      return lastTag;
+    }
+
+    @Override
+    public boolean skipField(final int tag) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          skipRawVarint();
+          return true;
+        case WireFormat.WIRETYPE_FIXED64:
+          skipRawBytes(FIXED64_SIZE);
+          return true;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          skipRawBytes(readRawVarint32());
+          return true;
+        case WireFormat.WIRETYPE_START_GROUP:
+          skipMessage();
+          checkLastTagWas(
+              WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+          return true;
+        case WireFormat.WIRETYPE_END_GROUP:
+          return false;
+        case WireFormat.WIRETYPE_FIXED32:
+          skipRawBytes(FIXED32_SIZE);
+          return true;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public boolean skipField(final int tag, final CodedOutputStream output) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          {
+            long value = readInt64();
+            output.writeRawVarint32(tag);
+            output.writeUInt64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_FIXED64:
+          {
+            long value = readRawLittleEndian64();
+            output.writeRawVarint32(tag);
+            output.writeFixed64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          {
+            ByteString value = readBytes();
+            output.writeRawVarint32(tag);
+            output.writeBytesNoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_START_GROUP:
+          {
+            output.writeRawVarint32(tag);
+            skipMessage(output);
+            int endtag =
+                WireFormat.makeTag(
+                    WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
+            checkLastTagWas(endtag);
+            output.writeRawVarint32(endtag);
+            return true;
+          }
+        case WireFormat.WIRETYPE_END_GROUP:
+          {
+            return false;
+          }
+        case WireFormat.WIRETYPE_FIXED32:
+          {
+            int value = readRawLittleEndian32();
+            output.writeRawVarint32(tag);
+            output.writeFixed32NoTag(value);
+            return true;
+          }
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public void skipMessage() throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag)) {
+          return;
+        }
+      }
+    }
+
+    @Override
+    public void skipMessage(CodedOutputStream output) throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag, output)) {
+          return;
+        }
+      }
+    }
+
+
+    // -----------------------------------------------------------------
+
+    @Override
+    public double readDouble() throws IOException {
+      return Double.longBitsToDouble(readRawLittleEndian64());
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+      return Float.intBitsToFloat(readRawLittleEndian32());
+    }
+
+    @Override
+    public long readUInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public long readInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public int readInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public long readFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public boolean readBool() throws IOException {
+      return readRawVarint64() != 0;
+    }
+
+    @Override
+    public String readString() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= (limit - pos)) {
+        // Fast path:  We already have the bytes in a contiguous buffer, so
+        //   just copy directly from it.
+        final String result = new String(buffer, pos, size, UTF_8);
+        pos += size;
+        return result;
+      }
+
+      if (size == 0) {
+        return "";
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public String readStringRequireUtf8() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= (limit - pos)) {
+        if (ENABLE_CUSTOM_UTF8_DECODE) {
+          String result = Utf8.decodeUtf8(buffer, pos, size);
+          pos += size;
+          return result;
+        } else {
+          // TODO(martinrb): We could save a pass by validating while decoding.
+          if (!Utf8.isValidUtf8(buffer, pos, pos + size)) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          final int tempPos = pos;
+          pos += size;
+          return new String(buffer, tempPos, size, UTF_8);
+        }
+      }
+
+      if (size == 0) {
+        return "";
+      }
+      if (size <= 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public void readGroup(
+        final int fieldNumber,
+        final MessageLite.Builder builder,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readGroup(
+        final int fieldNumber,
+        final Parser<T> parser,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+      return result;
+    }
+
+    @Deprecated
+    @Override
+    public void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+        throws IOException {
+      readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry());
+    }
+
+    @Override
+    public void readMessage(
+        final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readMessage(
+        final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+      return result;
+    }
+
+    @Override
+    public ByteString readBytes() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= (limit - pos)) {
+        // Fast path:  We already have the bytes in a contiguous buffer, so
+        //   just copy directly from it.
+        final ByteString result =
+            immutable && enableAliasing
+                ? ByteString.wrap(buffer, pos, size)
+                : ByteString.copyFrom(buffer, pos, size);
+        pos += size;
+        return result;
+      }
+      if (size == 0) {
+        return ByteString.EMPTY;
+      }
+      // Slow path:  Build a byte array first then copy it.
+      return ByteString.wrap(readRawBytes(size));
+    }
+
+    @Override
+    public byte[] readByteArray() throws IOException {
+      final int size = readRawVarint32();
+      return readRawBytes(size);
+    }
+
+    @Override
+    public ByteBuffer readByteBuffer() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= (limit - pos)) {
+        // Fast path: We already have the bytes in a contiguous buffer.
+        // When aliasing is enabled, we can return a ByteBuffer pointing directly
+        // into the underlying byte array without copy if the CodedInputStream is
+        // constructed from a byte array. If aliasing is disabled or the input is
+        // from an InputStream or ByteString, we have to make a copy of the bytes.
+        ByteBuffer result =
+            !immutable && enableAliasing
+                ? ByteBuffer.wrap(buffer, pos, size).slice()
+                : ByteBuffer.wrap(Arrays.copyOfRange(buffer, pos, pos + size));
+        pos += size;
+        // TODO(nathanmittler): Investigate making the ByteBuffer be made read-only
+        return result;
+      }
+
+      if (size == 0) {
+        return EMPTY_BYTE_BUFFER;
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public int readUInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readEnum() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readSFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public long readSFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readSInt32() throws IOException {
+      return decodeZigZag32(readRawVarint32());
+    }
+
+    @Override
+    public long readSInt64() throws IOException {
+      return decodeZigZag64(readRawVarint64());
+    }
+
+    // =================================================================
+
+    @Override
+    public int readRawVarint32() throws IOException {
+      // See implementation notes for readRawVarint64
+      fastpath:
+      {
+        int tempPos = pos;
+
+        if (limit == tempPos) {
+          break fastpath;
+        }
+
+        final byte[] buffer = this.buffer;
+        int x;
+        if ((x = buffer[tempPos++]) >= 0) {
+          pos = tempPos;
+          return x;
+        } else if (limit - tempPos < 9) {
+          break fastpath;
+        } else if ((x ^= (buffer[tempPos++] << 7)) < 0) {
+          x ^= (~0 << 7);
+        } else if ((x ^= (buffer[tempPos++] << 14)) >= 0) {
+          x ^= (~0 << 7) ^ (~0 << 14);
+        } else if ((x ^= (buffer[tempPos++] << 21)) < 0) {
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+        } else {
+          int y = buffer[tempPos++];
+          x ^= y << 28;
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+          if (y < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0) {
+            break fastpath; // Will throw malformedVarint()
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return (int) readRawVarint64SlowPath();
+    }
+
+    private void skipRawVarint() throws IOException {
+      if (limit - pos >= MAX_VARINT_SIZE) {
+        skipRawVarintFastPath();
+      } else {
+        skipRawVarintSlowPath();
+      }
+    }
+
+    private void skipRawVarintFastPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (buffer[pos++] >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    private void skipRawVarintSlowPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (readRawByte() >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public long readRawVarint64() throws IOException {
+      // Implementation notes:
+      //
+      // Optimized for one-byte values, expected to be common.
+      // The particular code below was selected from various candidates
+      // empirically, by winning VarintBenchmark.
+      //
+      // Sign extension of (signed) Java bytes is usually a nuisance, but
+      // we exploit it here to more easily obtain the sign of bytes read.
+      // Instead of cleaning up the sign extension bits by masking eagerly,
+      // we delay until we find the final (positive) byte, when we clear all
+      // accumulated bits with one xor.  We depend on javac to constant fold.
+      fastpath:
+      {
+        int tempPos = pos;
+
+        if (limit == tempPos) {
+          break fastpath;
+        }
+
+        final byte[] buffer = this.buffer;
+        long x;
+        int y;
+        if ((y = buffer[tempPos++]) >= 0) {
+          pos = tempPos;
+          return y;
+        } else if (limit - tempPos < 9) {
+          break fastpath;
+        } else if ((y ^= (buffer[tempPos++] << 7)) < 0) {
+          x = y ^ (~0 << 7);
+        } else if ((y ^= (buffer[tempPos++] << 14)) >= 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14));
+        } else if ((y ^= (buffer[tempPos++] << 21)) < 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+        } else if ((x = y ^ ((long) buffer[tempPos++] << 28)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+        } else if ((x ^= ((long) buffer[tempPos++] << 35)) < 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+        } else if ((x ^= ((long) buffer[tempPos++] << 42)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+        } else if ((x ^= ((long) buffer[tempPos++] << 49)) < 0L) {
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49);
+        } else {
+          x ^= ((long) buffer[tempPos++] << 56);
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49)
+                  ^ (~0L << 56);
+          if (x < 0L) {
+            if (buffer[tempPos++] < 0L) {
+              break fastpath; // Will throw malformedVarint()
+            }
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return readRawVarint64SlowPath();
+    }
+
+    @Override
+    long readRawVarint64SlowPath() throws IOException {
+      long result = 0;
+      for (int shift = 0; shift < 64; shift += 7) {
+        final byte b = readRawByte();
+        result |= (long) (b & 0x7F) << shift;
+        if ((b & 0x80) == 0) {
+          return result;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public int readRawLittleEndian32() throws IOException {
+      int tempPos = pos;
+
+      if (limit - tempPos < FIXED32_SIZE) {
+        throw InvalidProtocolBufferException.truncatedMessage();
       }
 
       final byte[] buffer = this.buffer;
-      long x;
-      int y;
-      if ((y = buffer[pos++]) >= 0) {
-        bufferPos = pos;
-        return y;
-      } else if (bufferSize - pos < 9) {
-        break fastpath;
-      } else if ((y ^= (buffer[pos++] << 7)) < 0) {
-        x = y ^ (~0 << 7);
-      } else if ((y ^= (buffer[pos++] << 14)) >= 0) {
-        x = y ^ ((~0 << 7) ^ (~0 << 14));
-      } else if ((y ^= (buffer[pos++] << 21)) < 0) {
-        x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
-      } else if ((x = ((long) y) ^ ((long) buffer[pos++] << 28)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
-      } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
-      } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
-      } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
-            ^ (~0L << 49);
+      pos = tempPos + FIXED32_SIZE;
+      return (((buffer[tempPos] & 0xff))
+          | ((buffer[tempPos + 1] & 0xff) << 8)
+          | ((buffer[tempPos + 2] & 0xff) << 16)
+          | ((buffer[tempPos + 3] & 0xff) << 24));
+    }
+
+    @Override
+    public long readRawLittleEndian64() throws IOException {
+      int tempPos = pos;
+
+      if (limit - tempPos < FIXED64_SIZE) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+
+      final byte[] buffer = this.buffer;
+      pos = tempPos + FIXED64_SIZE;
+      return (((buffer[tempPos] & 0xffL))
+          | ((buffer[tempPos + 1] & 0xffL) << 8)
+          | ((buffer[tempPos + 2] & 0xffL) << 16)
+          | ((buffer[tempPos + 3] & 0xffL) << 24)
+          | ((buffer[tempPos + 4] & 0xffL) << 32)
+          | ((buffer[tempPos + 5] & 0xffL) << 40)
+          | ((buffer[tempPos + 6] & 0xffL) << 48)
+          | ((buffer[tempPos + 7] & 0xffL) << 56));
+    }
+
+    @Override
+    public void enableAliasing(boolean enabled) {
+      this.enableAliasing = enabled;
+    }
+
+    @Override
+    public void resetSizeCounter() {
+      startPos = pos;
+    }
+
+    @Override
+    public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+      if (byteLimit < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      byteLimit += getTotalBytesRead();
+      final int oldLimit = currentLimit;
+      if (byteLimit > oldLimit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      currentLimit = byteLimit;
+
+      recomputeBufferSizeAfterLimit();
+
+      return oldLimit;
+    }
+
+    private void recomputeBufferSizeAfterLimit() {
+      limit += bufferSizeAfterLimit;
+      final int bufferEnd = limit - startPos;
+      if (bufferEnd > currentLimit) {
+        // Limit is in current buffer.
+        bufferSizeAfterLimit = bufferEnd - currentLimit;
+        limit -= bufferSizeAfterLimit;
       } else {
-        x ^= ((long) buffer[pos++] << 56);
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
-            ^ (~0L << 49) ^ (~0L << 56);
-        if (x < 0L) {
-          if (buffer[pos++] < 0L) {
-            break fastpath;  // Will throw malformedVarint()
-          }
+        bufferSizeAfterLimit = 0;
+      }
+    }
+
+    @Override
+    public void popLimit(final int oldLimit) {
+      currentLimit = oldLimit;
+      recomputeBufferSizeAfterLimit();
+    }
+
+    @Override
+    public int getBytesUntilLimit() {
+      if (currentLimit == Integer.MAX_VALUE) {
+        return -1;
+      }
+
+      return currentLimit - getTotalBytesRead();
+    }
+
+    @Override
+    public boolean isAtEnd() throws IOException {
+      return pos == limit;
+    }
+
+    @Override
+    public int getTotalBytesRead() {
+      return pos - startPos;
+    }
+
+    @Override
+    public byte readRawByte() throws IOException {
+      if (pos == limit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      return buffer[pos++];
+    }
+
+    @Override
+    public byte[] readRawBytes(final int length) throws IOException {
+      if (length > 0 && length <= (limit - pos)) {
+        final int tempPos = pos;
+        pos += length;
+        return Arrays.copyOfRange(buffer, tempPos, pos);
+      }
+
+      if (length <= 0) {
+        if (length == 0) {
+          return Internal.EMPTY_BYTE_ARRAY;
+        } else {
+          throw InvalidProtocolBufferException.negativeSize();
         }
       }
-      bufferPos = pos;
-      return x;
+      throw InvalidProtocolBufferException.truncatedMessage();
     }
-    return readRawVarint64SlowPath();
+
+    @Override
+    public void skipRawBytes(final int length) throws IOException {
+      if (length >= 0 && length <= (limit - pos)) {
+        // We have all the bytes we need already.
+        pos += length;
+        return;
+      }
+
+      if (length < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
   }
 
-  /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
-  /* Visible for testing */
-  long readRawVarint64SlowPath() throws IOException {
-    long result = 0;
-    for (int shift = 0; shift < 64; shift += 7) {
-      final byte b = readRawByte();
-      result |= (long) (b & 0x7F) << shift;
-      if ((b & 0x80) == 0) {
+  /**
+   * A {@link CodedInputStream} implementation that uses a backing direct ByteBuffer as the input.
+   * Requires the use of {@code sun.misc.Unsafe} to perform fast reads on the buffer.
+   */
+  private static final class UnsafeDirectNioDecoder extends CodedInputStream {
+    /** The direct buffer that is backing this stream. */
+    private final ByteBuffer buffer;
+
+    /**
+     * If {@code true}, indicates that the buffer is backing a {@link ByteString} and is therefore
+     * considered to be an immutable input source.
+     */
+    private final boolean immutable;
+
+    /** The unsafe address of the content of {@link #buffer}. */
+    private final long address;
+
+    /** The unsafe address of the current read limit of the buffer. */
+    private long limit;
+
+    /** The unsafe address of the current read position of the buffer. */
+    private long pos;
+
+    /** The unsafe address of the starting read position. */
+    private long startPos;
+
+    /** The amount of available data in the buffer beyond {@link #limit}. */
+    private int bufferSizeAfterLimit;
+
+    /** The last tag that was read from this stream. */
+    private int lastTag;
+
+    /**
+     * If {@code true}, indicates that calls to read {@link ByteString} or {@code byte[]}
+     * <strong>may</strong> return slices of the underlying buffer, rather than copies.
+     */
+    private boolean enableAliasing;
+
+    /** The absolute position of the end of the current message. */
+    private int currentLimit = Integer.MAX_VALUE;
+
+    static boolean isSupported() {
+      return UnsafeUtil.hasUnsafeByteBufferOperations();
+    }
+
+    private UnsafeDirectNioDecoder(ByteBuffer buffer, boolean immutable) {
+      this.buffer = buffer;
+      address = UnsafeUtil.addressOffset(buffer);
+      limit = address + buffer.limit();
+      pos = address + buffer.position();
+      startPos = pos;
+      this.immutable = immutable;
+    }
+
+    @Override
+    public int readTag() throws IOException {
+      if (isAtEnd()) {
+        lastTag = 0;
+        return 0;
+      }
+
+      lastTag = readRawVarint32();
+      if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+        // If we actually read zero (or any tag number corresponding to field
+        // number zero), that's not a valid tag.
+        throw InvalidProtocolBufferException.invalidTag();
+      }
+      return lastTag;
+    }
+
+    @Override
+    public void checkLastTagWas(final int value) throws InvalidProtocolBufferException {
+      if (lastTag != value) {
+        throw InvalidProtocolBufferException.invalidEndTag();
+      }
+    }
+
+    @Override
+    public int getLastTag() {
+      return lastTag;
+    }
+
+    @Override
+    public boolean skipField(final int tag) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          skipRawVarint();
+          return true;
+        case WireFormat.WIRETYPE_FIXED64:
+          skipRawBytes(FIXED64_SIZE);
+          return true;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          skipRawBytes(readRawVarint32());
+          return true;
+        case WireFormat.WIRETYPE_START_GROUP:
+          skipMessage();
+          checkLastTagWas(
+              WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+          return true;
+        case WireFormat.WIRETYPE_END_GROUP:
+          return false;
+        case WireFormat.WIRETYPE_FIXED32:
+          skipRawBytes(FIXED32_SIZE);
+          return true;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public boolean skipField(final int tag, final CodedOutputStream output) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          {
+            long value = readInt64();
+            output.writeRawVarint32(tag);
+            output.writeUInt64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_FIXED64:
+          {
+            long value = readRawLittleEndian64();
+            output.writeRawVarint32(tag);
+            output.writeFixed64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          {
+            ByteString value = readBytes();
+            output.writeRawVarint32(tag);
+            output.writeBytesNoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_START_GROUP:
+          {
+            output.writeRawVarint32(tag);
+            skipMessage(output);
+            int endtag =
+                WireFormat.makeTag(
+                    WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
+            checkLastTagWas(endtag);
+            output.writeRawVarint32(endtag);
+            return true;
+          }
+        case WireFormat.WIRETYPE_END_GROUP:
+          {
+            return false;
+          }
+        case WireFormat.WIRETYPE_FIXED32:
+          {
+            int value = readRawLittleEndian32();
+            output.writeRawVarint32(tag);
+            output.writeFixed32NoTag(value);
+            return true;
+          }
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public void skipMessage() throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag)) {
+          return;
+        }
+      }
+    }
+
+    @Override
+    public void skipMessage(CodedOutputStream output) throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag, output)) {
+          return;
+        }
+      }
+    }
+
+
+    // -----------------------------------------------------------------
+
+    @Override
+    public double readDouble() throws IOException {
+      return Double.longBitsToDouble(readRawLittleEndian64());
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+      return Float.intBitsToFloat(readRawLittleEndian32());
+    }
+
+    @Override
+    public long readUInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public long readInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public int readInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public long readFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public boolean readBool() throws IOException {
+      return readRawVarint64() != 0;
+    }
+
+    @Override
+    public String readString() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= remaining()) {
+        // TODO(nathanmittler): Is there a way to avoid this copy?
+        // TODO(anuraaga): It might be possible to share the optimized loop with
+        // readStringRequireUtf8 by implementing Java replacement logic there.
+        // The same as readBytes' logic
+        byte[] bytes = new byte[size];
+        UnsafeUtil.copyMemory(pos, bytes, 0, size);
+        String result = new String(bytes, UTF_8);
+        pos += size;
         return result;
       }
-    }
-    throw InvalidProtocolBufferException.malformedVarint();
-  }
 
-  /** Read a 32-bit little-endian integer from the stream. */
-  public int readRawLittleEndian32() throws IOException {
-    int pos = bufferPos;
-
-    // hand-inlined ensureAvailable(4);
-    if (bufferSize - pos < 4) {
-      refillBuffer(4);
-      pos = bufferPos;
-    }
-
-    final byte[] buffer = this.buffer;
-    bufferPos = pos + 4;
-    return (((buffer[pos]     & 0xff))       |
-            ((buffer[pos + 1] & 0xff) <<  8) |
-            ((buffer[pos + 2] & 0xff) << 16) |
-            ((buffer[pos + 3] & 0xff) << 24));
-  }
-
-  /** Read a 64-bit little-endian integer from the stream. */
-  public long readRawLittleEndian64() throws IOException {
-    int pos = bufferPos;
-
-    // hand-inlined ensureAvailable(8);
-    if (bufferSize - pos < 8) {
-      refillBuffer(8);
-      pos = bufferPos;
-    }
-
-    final byte[] buffer = this.buffer;
-    bufferPos = pos + 8;
-    return ((((long) buffer[pos]     & 0xffL))       |
-            (((long) buffer[pos + 1] & 0xffL) <<  8) |
-            (((long) buffer[pos + 2] & 0xffL) << 16) |
-            (((long) buffer[pos + 3] & 0xffL) << 24) |
-            (((long) buffer[pos + 4] & 0xffL) << 32) |
-            (((long) buffer[pos + 5] & 0xffL) << 40) |
-            (((long) buffer[pos + 6] & 0xffL) << 48) |
-            (((long) buffer[pos + 7] & 0xffL) << 56));
-  }
-
-  /**
-   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 32-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 32-bit integer.
-   */
-  public static int decodeZigZag32(final int n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  /**
-   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 64-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 64-bit integer.
-   */
-  public static long decodeZigZag64(final long n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  // -----------------------------------------------------------------
-
-  private final byte[] buffer;
-  private final boolean bufferIsImmutable;
-  private int bufferSize;
-  private int bufferSizeAfterLimit;
-  private int bufferPos;
-  private final InputStream input;
-  private int lastTag;
-  private boolean enableAliasing = false;
-
-  /**
-   * The total number of bytes read before the current buffer.  The total
-   * bytes read up to the current position can be computed as
-   * {@code totalBytesRetired + bufferPos}.  This value may be negative if
-   * reading started in the middle of the current buffer (e.g. if the
-   * constructor that takes a byte array and an offset was used).
-   */
-  private int totalBytesRetired;
-
-  /** The absolute position of the end of the current message. */
-  private int currentLimit = Integer.MAX_VALUE;
-
-  /** See setRecursionLimit() */
-  private int recursionDepth;
-  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
-
-  /** See setSizeLimit() */
-  private int sizeLimit = DEFAULT_SIZE_LIMIT;
-
-  private static final int DEFAULT_RECURSION_LIMIT = 100;
-  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
-  private static final int BUFFER_SIZE = 4096;
-
-  private CodedInputStream(final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) {
-    this.buffer = buffer;
-    bufferSize = off + len;
-    bufferPos = off;
-    totalBytesRetired = -off;
-    input = null;
-    this.bufferIsImmutable = bufferIsImmutable;
-  }
-
-  private CodedInputStream(final InputStream input) {
-    buffer = new byte[BUFFER_SIZE];
-    bufferSize = 0;
-    bufferPos = 0;
-    totalBytesRetired = 0;
-    this.input = input;
-    bufferIsImmutable = false;
-  }
-
-  public void enableAliasing(boolean enabled) {
-    this.enableAliasing = enabled;
-  }
-
-  /**
-   * Set the maximum message recursion depth.  In order to prevent malicious
-   * messages from causing stack overflows, {@code CodedInputStream} limits
-   * how deeply messages may be nested.  The default limit is 64.
-   *
-   * @return the old limit.
-   */
-  public int setRecursionLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Recursion limit cannot be negative: " + limit);
-    }
-    final int oldLimit = recursionLimit;
-    recursionLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Set the maximum message size.  In order to prevent malicious
-   * messages from exhausting memory or causing integer overflows,
-   * {@code CodedInputStream} limits how large a message may be.
-   * The default limit is 64MB.  You should set this limit as small
-   * as you can without harming your app's functionality.  Note that
-   * size limits only apply when reading from an {@code InputStream}, not
-   * when constructed around a raw byte array (nor with
-   * {@link ByteString#newCodedInput}).
-   * <p>
-   * If you want to read several messages from a single CodedInputStream, you
-   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
-   * size limit.
-   *
-   * @return the old limit.
-   */
-  public int setSizeLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Size limit cannot be negative: " + limit);
-    }
-    final int oldLimit = sizeLimit;
-    sizeLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
-   */
-  public void resetSizeCounter() {
-    totalBytesRetired = -bufferPos;
-  }
-
-  /**
-   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
-   * is called when descending into a length-delimited embedded message.
-   *
-   * <p>Note that {@code pushLimit()} does NOT affect how many bytes the
-   * {@code CodedInputStream} reads from an underlying {@code InputStream} when
-   * refreshing its buffer.  If you need to prevent reading past a certain
-   * point in the underlying {@code InputStream} (e.g. because you expect it to
-   * contain more data after the end of the message which you need to handle
-   * differently) then you must place a wrapper around your {@code InputStream}
-   * which limits the amount of data that can be read from it.
-   *
-   * @return the old limit.
-   */
-  public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
-    if (byteLimit < 0) {
-      throw InvalidProtocolBufferException.negativeSize();
-    }
-    byteLimit += totalBytesRetired + bufferPos;
-    final int oldLimit = currentLimit;
-    if (byteLimit > oldLimit) {
+      if (size == 0) {
+        return "";
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
       throw InvalidProtocolBufferException.truncatedMessage();
     }
-    currentLimit = byteLimit;
 
-    recomputeBufferSizeAfterLimit();
+    @Override
+    public String readStringRequireUtf8() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= remaining()) {
+        if (ENABLE_CUSTOM_UTF8_DECODE) {
+          final int bufferPos = bufferPos(pos);
+          String result = Utf8.decodeUtf8(buffer, bufferPos, size);
+          pos += size;
+          return result;
+        } else {
+          // TODO(nathanmittler): Is there a way to avoid this copy?
+          // The same as readBytes' logic
+          byte[] bytes = new byte[size];
+          UnsafeUtil.copyMemory(pos, bytes, 0, size);
+          // TODO(martinrb): We could save a pass by validating while decoding.
+          if (!Utf8.isValidUtf8(bytes)) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
 
-    return oldLimit;
-  }
-
-  private void recomputeBufferSizeAfterLimit() {
-    bufferSize += bufferSizeAfterLimit;
-    final int bufferEnd = totalBytesRetired + bufferSize;
-    if (bufferEnd > currentLimit) {
-      // Limit is in current buffer.
-      bufferSizeAfterLimit = bufferEnd - currentLimit;
-      bufferSize -= bufferSizeAfterLimit;
-    } else {
-      bufferSizeAfterLimit = 0;
-    }
-  }
-
-  /**
-   * Discards the current limit, returning to the previous limit.
-   *
-   * @param oldLimit The old limit, as returned by {@code pushLimit}.
-   */
-  public void popLimit(final int oldLimit) {
-    currentLimit = oldLimit;
-    recomputeBufferSizeAfterLimit();
-  }
-
-  /**
-   * Returns the number of bytes to be read before the current limit.
-   * If no limit is set, returns -1.
-   */
-  public int getBytesUntilLimit() {
-    if (currentLimit == Integer.MAX_VALUE) {
-      return -1;
-    }
-
-    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
-    return currentLimit - currentAbsolutePosition;
-  }
-
-  /**
-   * Returns true if the stream has reached the end of the input.  This is the
-   * case if either the end of the underlying input source has been reached or
-   * if the stream has reached a limit created using {@link #pushLimit(int)}.
-   */
-  public boolean isAtEnd() throws IOException {
-    return bufferPos == bufferSize && !tryRefillBuffer(1);
-  }
-
-  /**
-   * The total bytes read up to the current position. Calling
-   * {@link #resetSizeCounter()} resets this value to zero.
-   */
-  public int getTotalBytesRead() {
-      return totalBytesRetired + bufferPos;
-  }
-
-  private interface RefillCallback {
-    void onRefill();
-  }
-
-  private RefillCallback refillCallback = null;
-
-  /**
-   * Reads more bytes from the input, making at least {@code n} bytes available
-   * in the buffer.  Caller must ensure that the requested space is not yet
-   * available, and that the requested space is less than BUFFER_SIZE.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  private void refillBuffer(int n) throws IOException {
-    if (!tryRefillBuffer(n)) {
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-  }
-
-  /**
-   * Tries to read more bytes from the input, making at least {@code n} bytes
-   * available in the buffer.  Caller must ensure that the requested space is
-   * not yet available, and that the requested space is less than BUFFER_SIZE.
-   *
-   * @return {@code true} if the bytes could be made available; {@code false}
-   *         if the end of the stream or the current limit was reached.
-   */
-  private boolean tryRefillBuffer(int n) throws IOException {
-    if (bufferPos + n <= bufferSize) {
-      throw new IllegalStateException(
-          "refillBuffer() called when " + n +
-          " bytes were already available in buffer");
-    }
-
-    if (totalBytesRetired + bufferPos + n > currentLimit) {
-      // Oops, we hit a limit.
-      return false;
-    }
-
-    if (refillCallback != null) {
-      refillCallback.onRefill();
-    }
-
-    if (input != null) {
-      int pos = bufferPos;
-      if (pos > 0) {
-        if (bufferSize > pos) {
-          System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
+          String result = new String(bytes, UTF_8);
+          pos += size;
+          return result;
         }
-        totalBytesRetired += pos;
-        bufferSize -= pos;
-        bufferPos = 0;
       }
 
-      int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
+      if (size == 0) {
+        return "";
+      }
+      if (size <= 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public void readGroup(
+        final int fieldNumber,
+        final MessageLite.Builder builder,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readGroup(
+        final int fieldNumber,
+        final Parser<T> parser,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+      return result;
+    }
+
+    @Deprecated
+    @Override
+    public void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+        throws IOException {
+      readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry());
+    }
+
+    @Override
+    public void readMessage(
+        final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readMessage(
+        final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+      return result;
+    }
+
+    @Override
+    public ByteString readBytes() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= remaining()) {
+        if (immutable && enableAliasing) {
+          final ByteBuffer result = slice(pos, pos + size);
+          pos += size;
+          return ByteString.wrap(result);
+        } else {
+          // Use UnsafeUtil to copy the memory to bytes instead of using ByteBuffer ways.
+          byte[] bytes = new byte[size];
+          UnsafeUtil.copyMemory(pos, bytes, 0, size);
+          pos += size;
+          return ByteString.wrap(bytes);
+        }
+      }
+
+      if (size == 0) {
+        return ByteString.EMPTY;
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public byte[] readByteArray() throws IOException {
+      return readRawBytes(readRawVarint32());
+    }
+
+    @Override
+    public ByteBuffer readByteBuffer() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= remaining()) {
+        // "Immutable" implies that buffer is backing a ByteString.
+        // Disallow slicing in this case to prevent the caller from modifying the contents
+        // of the ByteString.
+        if (!immutable && enableAliasing) {
+          final ByteBuffer result = slice(pos, pos + size);
+          pos += size;
+          return result;
+        } else {
+          // The same as readBytes' logic
+          byte[] bytes = new byte[size];
+          UnsafeUtil.copyMemory(pos, bytes, 0, size);
+          pos += size;
+          return ByteBuffer.wrap(bytes);
+        }
+        // TODO(nathanmittler): Investigate making the ByteBuffer be made read-only
+      }
+
+      if (size == 0) {
+        return EMPTY_BYTE_BUFFER;
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public int readUInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readEnum() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readSFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public long readSFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readSInt32() throws IOException {
+      return decodeZigZag32(readRawVarint32());
+    }
+
+    @Override
+    public long readSInt64() throws IOException {
+      return decodeZigZag64(readRawVarint64());
+    }
+
+    // =================================================================
+
+    @Override
+    public int readRawVarint32() throws IOException {
+      // See implementation notes for readRawVarint64
+      fastpath:
+      {
+        long tempPos = pos;
+
+        if (limit == tempPos) {
+          break fastpath;
+        }
+
+        int x;
+        if ((x = UnsafeUtil.getByte(tempPos++)) >= 0) {
+          pos = tempPos;
+          return x;
+        } else if (limit - tempPos < 9) {
+          break fastpath;
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+          x ^= (~0 << 7);
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+          x ^= (~0 << 7) ^ (~0 << 14);
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+        } else {
+          int y = UnsafeUtil.getByte(tempPos++);
+          x ^= y << 28;
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+          if (y < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0) {
+            break fastpath; // Will throw malformedVarint()
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return (int) readRawVarint64SlowPath();
+    }
+
+    private void skipRawVarint() throws IOException {
+      if (remaining() >= MAX_VARINT_SIZE) {
+        skipRawVarintFastPath();
+      } else {
+        skipRawVarintSlowPath();
+      }
+    }
+
+    private void skipRawVarintFastPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (UnsafeUtil.getByte(pos++) >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    private void skipRawVarintSlowPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (readRawByte() >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public long readRawVarint64() throws IOException {
+      // Implementation notes:
+      //
+      // Optimized for one-byte values, expected to be common.
+      // The particular code below was selected from various candidates
+      // empirically, by winning VarintBenchmark.
+      //
+      // Sign extension of (signed) Java bytes is usually a nuisance, but
+      // we exploit it here to more easily obtain the sign of bytes read.
+      // Instead of cleaning up the sign extension bits by masking eagerly,
+      // we delay until we find the final (positive) byte, when we clear all
+      // accumulated bits with one xor.  We depend on javac to constant fold.
+      fastpath:
+      {
+        long tempPos = pos;
+
+        if (limit == tempPos) {
+          break fastpath;
+        }
+
+        long x;
+        int y;
+        if ((y = UnsafeUtil.getByte(tempPos++)) >= 0) {
+          pos = tempPos;
+          return y;
+        } else if (limit - tempPos < 9) {
+          break fastpath;
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+          x = y ^ (~0 << 7);
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14));
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+        } else if ((x = y ^ ((long) UnsafeUtil.getByte(tempPos++) << 28)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 35)) < 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 42)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 49)) < 0L) {
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49);
+        } else {
+          x ^= ((long) UnsafeUtil.getByte(tempPos++) << 56);
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49)
+                  ^ (~0L << 56);
+          if (x < 0L) {
+            if (UnsafeUtil.getByte(tempPos++) < 0L) {
+              break fastpath; // Will throw malformedVarint()
+            }
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return readRawVarint64SlowPath();
+    }
+
+    @Override
+    long readRawVarint64SlowPath() throws IOException {
+      long result = 0;
+      for (int shift = 0; shift < 64; shift += 7) {
+        final byte b = readRawByte();
+        result |= (long) (b & 0x7F) << shift;
+        if ((b & 0x80) == 0) {
+          return result;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public int readRawLittleEndian32() throws IOException {
+      long tempPos = pos;
+
+      if (limit - tempPos < FIXED32_SIZE) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+
+      pos = tempPos + FIXED32_SIZE;
+      return (((UnsafeUtil.getByte(tempPos) & 0xff))
+          | ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8)
+          | ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16)
+          | ((UnsafeUtil.getByte(tempPos + 3) & 0xff) << 24));
+    }
+
+    @Override
+    public long readRawLittleEndian64() throws IOException {
+      long tempPos = pos;
+
+      if (limit - tempPos < FIXED64_SIZE) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+
+      pos = tempPos + FIXED64_SIZE;
+      return (((UnsafeUtil.getByte(tempPos) & 0xffL))
+          | ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8)
+          | ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16)
+          | ((UnsafeUtil.getByte(tempPos + 3) & 0xffL) << 24)
+          | ((UnsafeUtil.getByte(tempPos + 4) & 0xffL) << 32)
+          | ((UnsafeUtil.getByte(tempPos + 5) & 0xffL) << 40)
+          | ((UnsafeUtil.getByte(tempPos + 6) & 0xffL) << 48)
+          | ((UnsafeUtil.getByte(tempPos + 7) & 0xffL) << 56));
+    }
+
+    @Override
+    public void enableAliasing(boolean enabled) {
+      this.enableAliasing = enabled;
+    }
+
+    @Override
+    public void resetSizeCounter() {
+      startPos = pos;
+    }
+
+    @Override
+    public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+      if (byteLimit < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      byteLimit += getTotalBytesRead();
+      final int oldLimit = currentLimit;
+      if (byteLimit > oldLimit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      currentLimit = byteLimit;
+
+      recomputeBufferSizeAfterLimit();
+
+      return oldLimit;
+    }
+
+    @Override
+    public void popLimit(final int oldLimit) {
+      currentLimit = oldLimit;
+      recomputeBufferSizeAfterLimit();
+    }
+
+    @Override
+    public int getBytesUntilLimit() {
+      if (currentLimit == Integer.MAX_VALUE) {
+        return -1;
+      }
+
+      return currentLimit - getTotalBytesRead();
+    }
+
+    @Override
+    public boolean isAtEnd() throws IOException {
+      return pos == limit;
+    }
+
+    @Override
+    public int getTotalBytesRead() {
+      return (int) (pos - startPos);
+    }
+
+    @Override
+    public byte readRawByte() throws IOException {
+      if (pos == limit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      return UnsafeUtil.getByte(pos++);
+    }
+
+    @Override
+    public byte[] readRawBytes(final int length) throws IOException {
+      if (length >= 0 && length <= remaining()) {
+        byte[] bytes = new byte[length];
+        slice(pos, pos + length).get(bytes);
+        pos += length;
+        return bytes;
+      }
+
+      if (length <= 0) {
+        if (length == 0) {
+          return EMPTY_BYTE_ARRAY;
+        } else {
+          throw InvalidProtocolBufferException.negativeSize();
+        }
+      }
+
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public void skipRawBytes(final int length) throws IOException {
+      if (length >= 0 && length <= remaining()) {
+        // We have all the bytes we need already.
+        pos += length;
+        return;
+      }
+
+      if (length < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    private void recomputeBufferSizeAfterLimit() {
+      limit += bufferSizeAfterLimit;
+      final int bufferEnd = (int) (limit - startPos);
+      if (bufferEnd > currentLimit) {
+        // Limit is in current buffer.
+        bufferSizeAfterLimit = bufferEnd - currentLimit;
+        limit -= bufferSizeAfterLimit;
+      } else {
+        bufferSizeAfterLimit = 0;
+      }
+    }
+
+    private int remaining() {
+      return (int) (limit - pos);
+    }
+
+    private int bufferPos(long pos) {
+      return (int) (pos - address);
+    }
+
+    private ByteBuffer slice(long begin, long end) throws IOException {
+      int prevPos = buffer.position();
+      int prevLimit = buffer.limit();
+      try {
+        buffer.position(bufferPos(begin));
+        buffer.limit(bufferPos(end));
+        return buffer.slice();
+      } catch (IllegalArgumentException e) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      } finally {
+        buffer.position(prevPos);
+        buffer.limit(prevLimit);
+      }
+    }
+  }
+
+  /**
+   * Implementation of {@link CodedInputStream} that uses an {@link InputStream} as the data source.
+   */
+  private static final class StreamDecoder extends CodedInputStream {
+    private final InputStream input;
+    private final byte[] buffer;
+    /** bufferSize represents how many bytes are currently filled in the buffer */
+    private int bufferSize;
+
+    private int bufferSizeAfterLimit;
+    private int pos;
+    private int lastTag;
+
+    /**
+     * The total number of bytes read before the current buffer. The total bytes read up to the
+     * current position can be computed as {@code totalBytesRetired + pos}. This value may be
+     * negative if reading started in the middle of the current buffer (e.g. if the constructor that
+     * takes a byte array and an offset was used).
+     */
+    private int totalBytesRetired;
+
+    /** The absolute position of the end of the current message. */
+    private int currentLimit = Integer.MAX_VALUE;
+
+    private StreamDecoder(final InputStream input, int bufferSize) {
+      checkNotNull(input, "input");
+      this.input = input;
+      this.buffer = new byte[bufferSize];
+      this.bufferSize = 0;
+      pos = 0;
+      totalBytesRetired = 0;
+    }
+
+    @Override
+    public int readTag() throws IOException {
+      if (isAtEnd()) {
+        lastTag = 0;
+        return 0;
+      }
+
+      lastTag = readRawVarint32();
+      if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+        // If we actually read zero (or any tag number corresponding to field
+        // number zero), that's not a valid tag.
+        throw InvalidProtocolBufferException.invalidTag();
+      }
+      return lastTag;
+    }
+
+    @Override
+    public void checkLastTagWas(final int value) throws InvalidProtocolBufferException {
+      if (lastTag != value) {
+        throw InvalidProtocolBufferException.invalidEndTag();
+      }
+    }
+
+    @Override
+    public int getLastTag() {
+      return lastTag;
+    }
+
+    @Override
+    public boolean skipField(final int tag) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          skipRawVarint();
+          return true;
+        case WireFormat.WIRETYPE_FIXED64:
+          skipRawBytes(FIXED64_SIZE);
+          return true;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          skipRawBytes(readRawVarint32());
+          return true;
+        case WireFormat.WIRETYPE_START_GROUP:
+          skipMessage();
+          checkLastTagWas(
+              WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+          return true;
+        case WireFormat.WIRETYPE_END_GROUP:
+          return false;
+        case WireFormat.WIRETYPE_FIXED32:
+          skipRawBytes(FIXED32_SIZE);
+          return true;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public boolean skipField(final int tag, final CodedOutputStream output) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          {
+            long value = readInt64();
+            output.writeRawVarint32(tag);
+            output.writeUInt64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_FIXED64:
+          {
+            long value = readRawLittleEndian64();
+            output.writeRawVarint32(tag);
+            output.writeFixed64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          {
+            ByteString value = readBytes();
+            output.writeRawVarint32(tag);
+            output.writeBytesNoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_START_GROUP:
+          {
+            output.writeRawVarint32(tag);
+            skipMessage(output);
+            int endtag =
+                WireFormat.makeTag(
+                    WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
+            checkLastTagWas(endtag);
+            output.writeRawVarint32(endtag);
+            return true;
+          }
+        case WireFormat.WIRETYPE_END_GROUP:
+          {
+            return false;
+          }
+        case WireFormat.WIRETYPE_FIXED32:
+          {
+            int value = readRawLittleEndian32();
+            output.writeRawVarint32(tag);
+            output.writeFixed32NoTag(value);
+            return true;
+          }
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public void skipMessage() throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag)) {
+          return;
+        }
+      }
+    }
+
+    @Override
+    public void skipMessage(CodedOutputStream output) throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag, output)) {
+          return;
+        }
+      }
+    }
+
+    /** Collects the bytes skipped and returns the data in a ByteBuffer. */
+    private class SkippedDataSink implements RefillCallback {
+      private int lastPos = pos;
+      private ByteArrayOutputStream byteArrayStream;
+
+      @Override
+      public void onRefill() {
+        if (byteArrayStream == null) {
+          byteArrayStream = new ByteArrayOutputStream();
+        }
+        byteArrayStream.write(buffer, lastPos, pos - lastPos);
+        lastPos = 0;
+      }
+
+      /** Gets skipped data in a ByteBuffer. This method should only be called once. */
+      ByteBuffer getSkippedData() {
+        if (byteArrayStream == null) {
+          return ByteBuffer.wrap(buffer, lastPos, pos - lastPos);
+        } else {
+          byteArrayStream.write(buffer, lastPos, pos);
+          return ByteBuffer.wrap(byteArrayStream.toByteArray());
+        }
+      }
+    }
+
+
+    // -----------------------------------------------------------------
+
+    @Override
+    public double readDouble() throws IOException {
+      return Double.longBitsToDouble(readRawLittleEndian64());
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+      return Float.intBitsToFloat(readRawLittleEndian32());
+    }
+
+    @Override
+    public long readUInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public long readInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public int readInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public long readFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public boolean readBool() throws IOException {
+      return readRawVarint64() != 0;
+    }
+
+    @Override
+    public String readString() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= (bufferSize - pos)) {
+        // Fast path:  We already have the bytes in a contiguous buffer, so
+        //   just copy directly from it.
+        final String result = new String(buffer, pos, size, UTF_8);
+        pos += size;
+        return result;
+      }
+      if (size == 0) {
+        return "";
+      }
+      if (size <= bufferSize) {
+        refillBuffer(size);
+        String result = new String(buffer, pos, size, UTF_8);
+        pos += size;
+        return result;
+      }
+      // Slow path:  Build a byte array first then copy it.
+      return new String(readRawBytesSlowPath(size), UTF_8);
+    }
+
+    @Override
+    public String readStringRequireUtf8() throws IOException {
+      final int size = readRawVarint32();
+      final byte[] bytes;
+      final int oldPos = pos;
+      final int tempPos;
+      if (size <= (bufferSize - oldPos) && size > 0) {
+        // Fast path:  We already have the bytes in a contiguous buffer, so
+        //   just copy directly from it.
+        bytes = buffer;
+        pos = oldPos + size;
+        tempPos = oldPos;
+      } else if (size == 0) {
+        return "";
+      } else if (size <= bufferSize) {
+        refillBuffer(size);
+        bytes = buffer;
+        tempPos = 0;
+        pos = tempPos + size;
+      } else {
+        // Slow path:  Build a byte array first then copy it.
+        bytes = readRawBytesSlowPath(size);
+        tempPos = 0;
+      }
+      if (ENABLE_CUSTOM_UTF8_DECODE) {
+        return Utf8.decodeUtf8(bytes, tempPos, size);
+      } else {
+        // TODO(martinrb): We could save a pass by validating while decoding.
+        if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) {
+          throw InvalidProtocolBufferException.invalidUtf8();
+        }
+        return new String(bytes, tempPos, size, UTF_8);
+      }
+    }
+
+    @Override
+    public void readGroup(
+        final int fieldNumber,
+        final MessageLite.Builder builder,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readGroup(
+        final int fieldNumber,
+        final Parser<T> parser,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+      return result;
+    }
+
+    @Deprecated
+    @Override
+    public void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+        throws IOException {
+      readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry());
+    }
+
+    @Override
+    public void readMessage(
+        final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readMessage(
+        final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+      return result;
+    }
+
+    @Override
+    public ByteString readBytes() throws IOException {
+      final int size = readRawVarint32();
+      if (size <= (bufferSize - pos) && size > 0) {
+        // Fast path:  We already have the bytes in a contiguous buffer, so
+        //   just copy directly from it.
+        final ByteString result = ByteString.copyFrom(buffer, pos, size);
+        pos += size;
+        return result;
+      }
+      if (size == 0) {
+        return ByteString.EMPTY;
+      }
+      return readBytesSlowPath(size);
+    }
+
+    @Override
+    public byte[] readByteArray() throws IOException {
+      final int size = readRawVarint32();
+      if (size <= (bufferSize - pos) && size > 0) {
+        // Fast path: We already have the bytes in a contiguous buffer, so
+        // just copy directly from it.
+        final byte[] result = Arrays.copyOfRange(buffer, pos, pos + size);
+        pos += size;
+        return result;
+      } else {
+        // Slow path: Build a byte array first then copy it.
+        return readRawBytesSlowPath(size);
+      }
+    }
+
+    @Override
+    public ByteBuffer readByteBuffer() throws IOException {
+      final int size = readRawVarint32();
+      if (size <= (bufferSize - pos) && size > 0) {
+        // Fast path: We already have the bytes in a contiguous buffer.
+        ByteBuffer result = ByteBuffer.wrap(Arrays.copyOfRange(buffer, pos, pos + size));
+        pos += size;
+        return result;
+      }
+      if (size == 0) {
+        return Internal.EMPTY_BYTE_BUFFER;
+      }
+      // Slow path: Build a byte array first then copy it.
+      return ByteBuffer.wrap(readRawBytesSlowPath(size));
+    }
+
+    @Override
+    public int readUInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readEnum() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readSFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public long readSFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readSInt32() throws IOException {
+      return decodeZigZag32(readRawVarint32());
+    }
+
+    @Override
+    public long readSInt64() throws IOException {
+      return decodeZigZag64(readRawVarint64());
+    }
+
+    // =================================================================
+
+    @Override
+    public int readRawVarint32() throws IOException {
+      // See implementation notes for readRawVarint64
+      fastpath:
+      {
+        int tempPos = pos;
+
+        if (bufferSize == tempPos) {
+          break fastpath;
+        }
+
+        final byte[] buffer = this.buffer;
+        int x;
+        if ((x = buffer[tempPos++]) >= 0) {
+          pos = tempPos;
+          return x;
+        } else if (bufferSize - tempPos < 9) {
+          break fastpath;
+        } else if ((x ^= (buffer[tempPos++] << 7)) < 0) {
+          x ^= (~0 << 7);
+        } else if ((x ^= (buffer[tempPos++] << 14)) >= 0) {
+          x ^= (~0 << 7) ^ (~0 << 14);
+        } else if ((x ^= (buffer[tempPos++] << 21)) < 0) {
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+        } else {
+          int y = buffer[tempPos++];
+          x ^= y << 28;
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+          if (y < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0
+              && buffer[tempPos++] < 0) {
+            break fastpath; // Will throw malformedVarint()
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return (int) readRawVarint64SlowPath();
+    }
+
+    private void skipRawVarint() throws IOException {
+      if (bufferSize - pos >= MAX_VARINT_SIZE) {
+        skipRawVarintFastPath();
+      } else {
+        skipRawVarintSlowPath();
+      }
+    }
+
+    private void skipRawVarintFastPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (buffer[pos++] >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    private void skipRawVarintSlowPath() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (readRawByte() >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public long readRawVarint64() throws IOException {
+      // Implementation notes:
+      //
+      // Optimized for one-byte values, expected to be common.
+      // The particular code below was selected from various candidates
+      // empirically, by winning VarintBenchmark.
+      //
+      // Sign extension of (signed) Java bytes is usually a nuisance, but
+      // we exploit it here to more easily obtain the sign of bytes read.
+      // Instead of cleaning up the sign extension bits by masking eagerly,
+      // we delay until we find the final (positive) byte, when we clear all
+      // accumulated bits with one xor.  We depend on javac to constant fold.
+      fastpath:
+      {
+        int tempPos = pos;
+
+        if (bufferSize == tempPos) {
+          break fastpath;
+        }
+
+        final byte[] buffer = this.buffer;
+        long x;
+        int y;
+        if ((y = buffer[tempPos++]) >= 0) {
+          pos = tempPos;
+          return y;
+        } else if (bufferSize - tempPos < 9) {
+          break fastpath;
+        } else if ((y ^= (buffer[tempPos++] << 7)) < 0) {
+          x = y ^ (~0 << 7);
+        } else if ((y ^= (buffer[tempPos++] << 14)) >= 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14));
+        } else if ((y ^= (buffer[tempPos++] << 21)) < 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+        } else if ((x = y ^ ((long) buffer[tempPos++] << 28)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+        } else if ((x ^= ((long) buffer[tempPos++] << 35)) < 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+        } else if ((x ^= ((long) buffer[tempPos++] << 42)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+        } else if ((x ^= ((long) buffer[tempPos++] << 49)) < 0L) {
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49);
+        } else {
+          x ^= ((long) buffer[tempPos++] << 56);
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49)
+                  ^ (~0L << 56);
+          if (x < 0L) {
+            if (buffer[tempPos++] < 0L) {
+              break fastpath; // Will throw malformedVarint()
+            }
+          }
+        }
+        pos = tempPos;
+        return x;
+      }
+      return readRawVarint64SlowPath();
+    }
+
+    @Override
+    long readRawVarint64SlowPath() throws IOException {
+      long result = 0;
+      for (int shift = 0; shift < 64; shift += 7) {
+        final byte b = readRawByte();
+        result |= (long) (b & 0x7F) << shift;
+        if ((b & 0x80) == 0) {
+          return result;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public int readRawLittleEndian32() throws IOException {
+      int tempPos = pos;
+
+      if (bufferSize - tempPos < FIXED32_SIZE) {
+        refillBuffer(FIXED32_SIZE);
+        tempPos = pos;
+      }
+
+      final byte[] buffer = this.buffer;
+      pos = tempPos + FIXED32_SIZE;
+      return (((buffer[tempPos] & 0xff))
+          | ((buffer[tempPos + 1] & 0xff) << 8)
+          | ((buffer[tempPos + 2] & 0xff) << 16)
+          | ((buffer[tempPos + 3] & 0xff) << 24));
+    }
+
+    @Override
+    public long readRawLittleEndian64() throws IOException {
+      int tempPos = pos;
+
+      if (bufferSize - tempPos < FIXED64_SIZE) {
+        refillBuffer(FIXED64_SIZE);
+        tempPos = pos;
+      }
+
+      final byte[] buffer = this.buffer;
+      pos = tempPos + FIXED64_SIZE;
+      return (((buffer[tempPos] & 0xffL))
+          | ((buffer[tempPos + 1] & 0xffL) << 8)
+          | ((buffer[tempPos + 2] & 0xffL) << 16)
+          | ((buffer[tempPos + 3] & 0xffL) << 24)
+          | ((buffer[tempPos + 4] & 0xffL) << 32)
+          | ((buffer[tempPos + 5] & 0xffL) << 40)
+          | ((buffer[tempPos + 6] & 0xffL) << 48)
+          | ((buffer[tempPos + 7] & 0xffL) << 56));
+    }
+
+    // -----------------------------------------------------------------
+
+    @Override
+    public void enableAliasing(boolean enabled) {
+      // TODO(nathanmittler): Ideally we should throw here. Do nothing for backward compatibility.
+    }
+
+    @Override
+    public void resetSizeCounter() {
+      totalBytesRetired = -pos;
+    }
+
+    @Override
+    public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+      if (byteLimit < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      byteLimit += totalBytesRetired + pos;
+      final int oldLimit = currentLimit;
+      if (byteLimit > oldLimit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      currentLimit = byteLimit;
+
+      recomputeBufferSizeAfterLimit();
+
+      return oldLimit;
+    }
+
+    private void recomputeBufferSizeAfterLimit() {
+      bufferSize += bufferSizeAfterLimit;
+      final int bufferEnd = totalBytesRetired + bufferSize;
+      if (bufferEnd > currentLimit) {
+        // Limit is in current buffer.
+        bufferSizeAfterLimit = bufferEnd - currentLimit;
+        bufferSize -= bufferSizeAfterLimit;
+      } else {
+        bufferSizeAfterLimit = 0;
+      }
+    }
+
+    @Override
+    public void popLimit(final int oldLimit) {
+      currentLimit = oldLimit;
+      recomputeBufferSizeAfterLimit();
+    }
+
+    @Override
+    public int getBytesUntilLimit() {
+      if (currentLimit == Integer.MAX_VALUE) {
+        return -1;
+      }
+
+      final int currentAbsolutePosition = totalBytesRetired + pos;
+      return currentLimit - currentAbsolutePosition;
+    }
+
+    @Override
+    public boolean isAtEnd() throws IOException {
+      return pos == bufferSize && !tryRefillBuffer(1);
+    }
+
+    @Override
+    public int getTotalBytesRead() {
+      return totalBytesRetired + pos;
+    }
+
+    private interface RefillCallback {
+      void onRefill();
+    }
+
+    private RefillCallback refillCallback = null;
+
+    /**
+     * Reads more bytes from the input, making at least {@code n} bytes available in the buffer.
+     * Caller must ensure that the requested space is not yet available, and that the requested
+     * space is less than BUFFER_SIZE.
+     *
+     * @throws InvalidProtocolBufferException The end of the stream or the current limit was
+     *     reached.
+     */
+    private void refillBuffer(int n) throws IOException {
+      if (!tryRefillBuffer(n)) {
+        // We have to distinguish the exception between sizeLimitExceeded and truncatedMessage. So
+        // we just throw an sizeLimitExceeded exception here if it exceeds the sizeLimit
+        if (n > sizeLimit - totalBytesRetired - pos) {
+          throw InvalidProtocolBufferException.sizeLimitExceeded();
+        } else {
+          throw InvalidProtocolBufferException.truncatedMessage();
+        }
+      }
+    }
+
+    /**
+     * Tries to read more bytes from the input, making at least {@code n} bytes available in the
+     * buffer. Caller must ensure that the requested space is not yet available, and that the
+     * requested space is less than BUFFER_SIZE.
+     *
+     * @return {@code true} If the bytes could be made available; {@code false} 1. Current at the
+     *     end of the stream 2. The current limit was reached 3. The total size limit was reached
+     */
+    private boolean tryRefillBuffer(int n) throws IOException {
+      if (pos + n <= bufferSize) {
+        throw new IllegalStateException(
+            "refillBuffer() called when " + n + " bytes were already available in buffer");
+      }
+
+      // Check whether the size of total message needs to read is bigger than the size limit.
+      // We shouldn't throw an exception here as isAtEnd() function needs to get this function's
+      // return as the result.
+      if (n > sizeLimit - totalBytesRetired - pos) {
+        return false;
+      }
+
+      // Shouldn't throw the exception here either.
+      if (totalBytesRetired + pos + n > currentLimit) {
+        // Oops, we hit a limit.
+        return false;
+      }
+
+      if (refillCallback != null) {
+        refillCallback.onRefill();
+      }
+
+      int tempPos = pos;
+      if (tempPos > 0) {
+        if (bufferSize > tempPos) {
+          System.arraycopy(buffer, tempPos, buffer, 0, bufferSize - tempPos);
+        }
+        totalBytesRetired += tempPos;
+        bufferSize -= tempPos;
+        pos = 0;
+      }
+
+      // Here we should refill the buffer as many bytes as possible.
+      int bytesRead =
+          input.read(
+              buffer,
+              bufferSize,
+              Math.min(
+                  //  the size of allocated but unused bytes in the buffer
+                  buffer.length - bufferSize,
+                  //  do not exceed the total bytes limit
+                  sizeLimit - totalBytesRetired - bufferSize));
       if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
         throw new IllegalStateException(
-            "InputStream#read(byte[]) returned invalid result: " + bytesRead +
-            "\nThe InputStream implementation is buggy.");
+            "InputStream#read(byte[]) returned invalid result: "
+                + bytesRead
+                + "\nThe InputStream implementation is buggy.");
       }
       if (bytesRead > 0) {
         bufferSize += bytesRead;
-        // Integer-overflow-conscious check against sizeLimit
-        if (totalBytesRetired + n - sizeLimit > 0) {
-          throw InvalidProtocolBufferException.sizeLimitExceeded();
-        }
         recomputeBufferSizeAfterLimit();
         return (bufferSize >= n) ? true : tryRefillBuffer(n);
       }
+
+      return false;
     }
 
-    return false;
-  }
-
-  /**
-   * Read one byte from the input.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte readRawByte() throws IOException {
-    if (bufferPos == bufferSize) {
-      refillBuffer(1);
+    @Override
+    public byte readRawByte() throws IOException {
+      if (pos == bufferSize) {
+        refillBuffer(1);
+      }
+      return buffer[pos++];
     }
-    return buffer[bufferPos++];
-  }
 
-  /**
-   * Read a fixed size of bytes from the input.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte[] readRawBytes(final int size) throws IOException {
-    final int pos = bufferPos;
-    if (size <= (bufferSize - pos) && size > 0) {
-      bufferPos = pos + size;
-      return Arrays.copyOfRange(buffer, pos, pos + size);
-    } else {
-      return readRawBytesSlowPath(size);
-    }
-  }
-
-  /**
-   * Exactly like readRawBytes, but caller must have already checked the fast
-   * path: (size <= (bufferSize - pos) && size > 0)
-   */
-  private byte[] readRawBytesSlowPath(final int size) throws IOException {
-    if (size <= 0) {
-      if (size == 0) {
-        return Internal.EMPTY_BYTE_ARRAY;
+    @Override
+    public byte[] readRawBytes(final int size) throws IOException {
+      final int tempPos = pos;
+      if (size <= (bufferSize - tempPos) && size > 0) {
+        pos = tempPos + size;
+        return Arrays.copyOfRange(buffer, tempPos, tempPos + size);
       } else {
-        throw InvalidProtocolBufferException.negativeSize();
+        return readRawBytesSlowPath(size);
       }
     }
 
-    // Verify that the message size so far has not exceeded sizeLimit.
-    int currentMessageSize = totalBytesRetired + bufferPos + size;
-    if (currentMessageSize > sizeLimit) {
-      throw InvalidProtocolBufferException.sizeLimitExceeded();
-    }
+    /**
+     * Exactly like readRawBytes, but caller must have already checked the fast path: (size <=
+     * (bufferSize - pos) && size > 0)
+     */
+    private byte[] readRawBytesSlowPath(final int size) throws IOException {
+      // Attempt to read the data in one byte array when it's safe to do.
+      byte[] result = readRawBytesSlowPathOneChunk(size);
+      if (result != null) {
+        return result;
+      }
 
-    // Verify that the message size so far has not exceeded currentLimit.
-    if (currentMessageSize > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
+      final int originalBufferPos = pos;
+      final int bufferedBytes = bufferSize - pos;
 
-    // We need the input stream to proceed.
-    if (input == null) {
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
+      // Mark the current buffer consumed.
+      totalBytesRetired += bufferSize;
+      pos = 0;
+      bufferSize = 0;
 
-    final int originalBufferPos = bufferPos;
-    final int bufferedBytes = bufferSize - bufferPos;
+      // Determine the number of bytes we need to read from the input stream.
+      int sizeLeft = size - bufferedBytes;
 
-    // Mark the current buffer consumed.
-    totalBytesRetired += bufferSize;
-    bufferPos = 0;
-    bufferSize = 0;
+      // The size is very large. For security reasons we read them in small
+      // chunks.
+      List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
 
-    // Determine the number of bytes we need to read from the input stream.
-    int sizeLeft = size - bufferedBytes;
-    // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
-    if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) {
-      // Either the bytes we need are known to be available, or the required buffer is
-      // within an allowed threshold - go ahead and allocate the buffer now.
+      // OK, got everything.  Now concatenate it all into one buffer.
       final byte[] bytes = new byte[size];
 
-      // Copy all of the buffered bytes to the result buffer.
+      // Start by copying the leftover bytes from this.buffer.
       System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
 
-      // Fill the remaining bytes from the input stream.
-      int pos = bufferedBytes;
-      while (pos < bytes.length) {
-        int n = input.read(bytes, pos, size - pos);
-        if (n == -1) {
-          throw InvalidProtocolBufferException.truncatedMessage();
-        }
-        totalBytesRetired += n;
-        pos += n;
+      // And now all the chunks.
+      int tempPos = bufferedBytes;
+      for (final byte[] chunk : chunks) {
+        System.arraycopy(chunk, 0, bytes, tempPos, chunk.length);
+        tempPos += chunk.length;
       }
 
+      // Done.
       return bytes;
     }
 
-    // The size is very large.  For security reasons, we can't allocate the
-    // entire byte array yet.  The size comes directly from the input, so a
-    // maliciously-crafted message could provide a bogus very large size in
-    // order to trick the app into allocating a lot of memory.  We avoid this
-    // by allocating and reading only a small chunk at a time, so that the
-    // malicious message must actually *be* extremely large to cause
-    // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
-    final List<byte[]> chunks = new ArrayList<byte[]>();
-
-    while (sizeLeft > 0) {
-      // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
-      final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
-      int pos = 0;
-      while (pos < chunk.length) {
-        final int n = input.read(chunk, pos, chunk.length - pos);
-        if (n == -1) {
-          throw InvalidProtocolBufferException.truncatedMessage();
-        }
-        totalBytesRetired += n;
-        pos += n;
+    /**
+     * Attempts to read the data in one byte array when it's safe to do. Returns null if the size to
+     * read is too large and needs to be allocated in smaller chunks for security reasons.
+     */
+    private byte[] readRawBytesSlowPathOneChunk(final int size) throws IOException {
+      if (size == 0) {
+        return Internal.EMPTY_BYTE_ARRAY;
       }
-      sizeLeft -= chunk.length;
-      chunks.add(chunk);
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+
+      // Integer-overflow-conscious check that the message size so far has not exceeded sizeLimit.
+      int currentMessageSize = totalBytesRetired + pos + size;
+      if (currentMessageSize - sizeLimit > 0) {
+        throw InvalidProtocolBufferException.sizeLimitExceeded();
+      }
+
+      // Verify that the message size so far has not exceeded currentLimit.
+      if (currentMessageSize > currentLimit) {
+        // Read to the end of the stream anyway.
+        skipRawBytes(currentLimit - totalBytesRetired - pos);
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+
+      final int bufferedBytes = bufferSize - pos;
+      // Determine the number of bytes we need to read from the input stream.
+      int sizeLeft = size - bufferedBytes;
+      // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_SIZE.
+      if (sizeLeft < DEFAULT_BUFFER_SIZE || sizeLeft <= input.available()) {
+        // Either the bytes we need are known to be available, or the required buffer is
+        // within an allowed threshold - go ahead and allocate the buffer now.
+        final byte[] bytes = new byte[size];
+
+        // Copy all of the buffered bytes to the result buffer.
+        System.arraycopy(buffer, pos, bytes, 0, bufferedBytes);
+        totalBytesRetired += bufferSize;
+        pos = 0;
+        bufferSize = 0;
+
+        // Fill the remaining bytes from the input stream.
+        int tempPos = bufferedBytes;
+        while (tempPos < bytes.length) {
+          int n = input.read(bytes, tempPos, size - tempPos);
+          if (n == -1) {
+            throw InvalidProtocolBufferException.truncatedMessage();
+          }
+          totalBytesRetired += n;
+          tempPos += n;
+        }
+
+        return bytes;
+      }
+
+      return null;
     }
 
-    // OK, got everything.  Now concatenate it all into one buffer.
-    final byte[] bytes = new byte[size];
+    /** Reads the remaining data in small chunks from the input stream. */
+    private List<byte[]> readRawBytesSlowPathRemainingChunks(int sizeLeft) throws IOException {
+      // The size is very large.  For security reasons, we can't allocate the
+      // entire byte array yet.  The size comes directly from the input, so a
+      // maliciously-crafted message could provide a bogus very large size in
+      // order to trick the app into allocating a lot of memory.  We avoid this
+      // by allocating and reading only a small chunk at a time, so that the
+      // malicious message must actually *be* extremely large to cause
+      // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+      final List<byte[]> chunks = new ArrayList<byte[]>();
 
-    // Start by copying the leftover bytes from this.buffer.
-    System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+      while (sizeLeft > 0) {
+        // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_SIZE.
+        final byte[] chunk = new byte[Math.min(sizeLeft, DEFAULT_BUFFER_SIZE)];
+        int tempPos = 0;
+        while (tempPos < chunk.length) {
+          final int n = input.read(chunk, tempPos, chunk.length - tempPos);
+          if (n == -1) {
+            throw InvalidProtocolBufferException.truncatedMessage();
+          }
+          totalBytesRetired += n;
+          tempPos += n;
+        }
+        sizeLeft -= chunk.length;
+        chunks.add(chunk);
+      }
 
-    // And now all the chunks.
-    int pos = bufferedBytes;
-    for (final byte[] chunk : chunks) {
-      System.arraycopy(chunk, 0, bytes, pos, chunk.length);
-      pos += chunk.length;
+      return chunks;
     }
 
-    // Done.
-    return bytes;
-  }
+    /**
+     * Like readBytes, but caller must have already checked the fast path: (size <= (bufferSize -
+     * pos) && size > 0 || size == 0)
+     */
+    private ByteString readBytesSlowPath(final int size) throws IOException {
+      final byte[] result = readRawBytesSlowPathOneChunk(size);
+      if (result != null) {
+        return ByteString.wrap(result);
+      }
 
-  /**
-   * Reads and discards {@code size} bytes.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public void skipRawBytes(final int size) throws IOException {
-    if (size <= (bufferSize - bufferPos) && size >= 0) {
-      // We have all the bytes we need already.
-      bufferPos += size;
-    } else {
-      skipRawBytesSlowPath(size);
+      final int originalBufferPos = pos;
+      final int bufferedBytes = bufferSize - pos;
+
+      // Mark the current buffer consumed.
+      totalBytesRetired += bufferSize;
+      pos = 0;
+      bufferSize = 0;
+
+      // Determine the number of bytes we need to read from the input stream.
+      int sizeLeft = size - bufferedBytes;
+
+      // The size is very large. For security reasons we read them in small
+      // chunks.
+      List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
+
+      // Wrap the byte arrays into a single ByteString.
+      List<ByteString> byteStrings = new ArrayList<ByteString>(1 + chunks.size());
+      byteStrings.add(ByteString.copyFrom(buffer, originalBufferPos, bufferedBytes));
+      for (byte[] chunk : chunks) {
+        byteStrings.add(ByteString.wrap(chunk));
+      }
+      return ByteString.copyFrom(byteStrings);
+    }
+
+    @Override
+    public void skipRawBytes(final int size) throws IOException {
+      if (size <= (bufferSize - pos) && size >= 0) {
+        // We have all the bytes we need already.
+        pos += size;
+      } else {
+        skipRawBytesSlowPath(size);
+      }
+    }
+
+    /**
+     * Exactly like skipRawBytes, but caller must have already checked the fast path: (size <=
+     * (bufferSize - pos) && size >= 0)
+     */
+    private void skipRawBytesSlowPath(final int size) throws IOException {
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+
+      if (totalBytesRetired + pos + size > currentLimit) {
+        // Read to the end of the stream anyway.
+        skipRawBytes(currentLimit - totalBytesRetired - pos);
+        // Then fail.
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+
+      // Skipping more bytes than are in the buffer.  First skip what we have.
+      int tempPos = bufferSize - pos;
+      pos = bufferSize;
+
+      // Keep refilling the buffer until we get to the point we wanted to skip to.
+      // This has the side effect of ensuring the limits are updated correctly.
+      refillBuffer(1);
+      while (size - tempPos > bufferSize) {
+        tempPos += bufferSize;
+        pos = bufferSize;
+        refillBuffer(1);
+      }
+
+      pos = size - tempPos;
     }
   }
 
   /**
-   * Exactly like skipRawBytes, but caller must have already checked the fast
-   * path: (size <= (bufferSize - pos) && size >= 0)
+   * Implementation of {@link CodedInputStream} that uses an {@link Iterable <ByteBuffer>} as the
+   * data source. Requires the use of {@code sun.misc.Unsafe} to perform fast reads on the buffer.
    */
-  private void skipRawBytesSlowPath(final int size) throws IOException {
-    if (size < 0) {
-      throw InvalidProtocolBufferException.negativeSize();
+  private static final class IterableDirectByteBufferDecoder extends CodedInputStream {
+    /** The object that need to decode. */
+    private Iterable<ByteBuffer> input;
+    /** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */
+    private Iterator<ByteBuffer> iterator;
+    /** The current ByteBuffer; */
+    private ByteBuffer currentByteBuffer;
+    /**
+     * If {@code true}, indicates that all the buffer are backing a {@link ByteString} and are
+     * therefore considered to be an immutable input source.
+     */
+    private boolean immutable;
+    /**
+     * If {@code true}, indicates that calls to read {@link ByteString} or {@code byte[]}
+     * <strong>may</strong> return slices of the underlying buffer, rather than copies.
+     */
+    private boolean enableAliasing;
+    /** The global total message length limit */
+    private int totalBufferSize;
+    /** The amount of available data in the input beyond {@link #currentLimit}. */
+    private int bufferSizeAfterCurrentLimit;
+    /** The absolute position of the end of the current message. */
+    private int currentLimit = Integer.MAX_VALUE;
+    /** The last tag that was read from this stream. */
+    private int lastTag;
+    /** Total Bytes have been Read from the {@link Iterable} {@link ByteBuffer} */
+    private int totalBytesRead;
+    /** The start position offset of the whole message, used as to reset the totalBytesRead */
+    private int startOffset;
+    /** The current position for current ByteBuffer */
+    private long currentByteBufferPos;
+
+    private long currentByteBufferStartPos;
+    /**
+     * If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this
+     * ByteBuffer; otherwise should be zero.
+     */
+    private long currentAddress;
+    /** The limit position for current ByteBuffer */
+    private long currentByteBufferLimit;
+
+    /**
+     * The constructor of {@code Iterable<ByteBuffer>} decoder.
+     *
+     * @param inputBufs The input data.
+     * @param size The total size of the input data.
+     * @param immutableFlag whether the input data is immutable.
+     */
+    private IterableDirectByteBufferDecoder(
+        Iterable<ByteBuffer> inputBufs, int size, boolean immutableFlag) {
+      totalBufferSize = size;
+      input = inputBufs;
+      iterator = input.iterator();
+      immutable = immutableFlag;
+      startOffset = totalBytesRead = 0;
+      if (size == 0) {
+        currentByteBuffer = EMPTY_BYTE_BUFFER;
+        currentByteBufferPos = 0;
+        currentByteBufferStartPos = 0;
+        currentByteBufferLimit = 0;
+        currentAddress = 0;
+      } else {
+        tryGetNextByteBuffer();
+      }
     }
 
-    if (totalBytesRetired + bufferPos + size > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
-      // Then fail.
+    /** To get the next ByteBuffer from {@code input}, and then update the parameters */
+    private void getNextByteBuffer() throws InvalidProtocolBufferException {
+      if (!iterator.hasNext()) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      tryGetNextByteBuffer();
+    }
+
+    private void tryGetNextByteBuffer() {
+      currentByteBuffer = iterator.next();
+      totalBytesRead += (int) (currentByteBufferPos - currentByteBufferStartPos);
+      currentByteBufferPos = currentByteBuffer.position();
+      currentByteBufferStartPos = currentByteBufferPos;
+      currentByteBufferLimit = currentByteBuffer.limit();
+      currentAddress = UnsafeUtil.addressOffset(currentByteBuffer);
+      currentByteBufferPos += currentAddress;
+      currentByteBufferStartPos += currentAddress;
+      currentByteBufferLimit += currentAddress;
+    }
+
+    @Override
+    public int readTag() throws IOException {
+      if (isAtEnd()) {
+        lastTag = 0;
+        return 0;
+      }
+
+      lastTag = readRawVarint32();
+      if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+        // If we actually read zero (or any tag number corresponding to field
+        // number zero), that's not a valid tag.
+        throw InvalidProtocolBufferException.invalidTag();
+      }
+      return lastTag;
+    }
+
+    @Override
+    public void checkLastTagWas(final int value) throws InvalidProtocolBufferException {
+      if (lastTag != value) {
+        throw InvalidProtocolBufferException.invalidEndTag();
+      }
+    }
+
+    @Override
+    public int getLastTag() {
+      return lastTag;
+    }
+
+    @Override
+    public boolean skipField(final int tag) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          skipRawVarint();
+          return true;
+        case WireFormat.WIRETYPE_FIXED64:
+          skipRawBytes(FIXED64_SIZE);
+          return true;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          skipRawBytes(readRawVarint32());
+          return true;
+        case WireFormat.WIRETYPE_START_GROUP:
+          skipMessage();
+          checkLastTagWas(
+              WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
+          return true;
+        case WireFormat.WIRETYPE_END_GROUP:
+          return false;
+        case WireFormat.WIRETYPE_FIXED32:
+          skipRawBytes(FIXED32_SIZE);
+          return true;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public boolean skipField(final int tag, final CodedOutputStream output) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          {
+            long value = readInt64();
+            output.writeRawVarint32(tag);
+            output.writeUInt64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_FIXED64:
+          {
+            long value = readRawLittleEndian64();
+            output.writeRawVarint32(tag);
+            output.writeFixed64NoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          {
+            ByteString value = readBytes();
+            output.writeRawVarint32(tag);
+            output.writeBytesNoTag(value);
+            return true;
+          }
+        case WireFormat.WIRETYPE_START_GROUP:
+          {
+            output.writeRawVarint32(tag);
+            skipMessage(output);
+            int endtag =
+                WireFormat.makeTag(
+                    WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
+            checkLastTagWas(endtag);
+            output.writeRawVarint32(endtag);
+            return true;
+          }
+        case WireFormat.WIRETYPE_END_GROUP:
+          {
+            return false;
+          }
+        case WireFormat.WIRETYPE_FIXED32:
+          {
+            int value = readRawLittleEndian32();
+            output.writeRawVarint32(tag);
+            output.writeFixed32NoTag(value);
+            return true;
+          }
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    @Override
+    public void skipMessage() throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag)) {
+          return;
+        }
+      }
+    }
+
+    @Override
+    public void skipMessage(CodedOutputStream output) throws IOException {
+      while (true) {
+        final int tag = readTag();
+        if (tag == 0 || !skipField(tag, output)) {
+          return;
+        }
+      }
+    }
+
+    // -----------------------------------------------------------------
+
+    @Override
+    public double readDouble() throws IOException {
+      return Double.longBitsToDouble(readRawLittleEndian64());
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+      return Float.intBitsToFloat(readRawLittleEndian32());
+    }
+
+    @Override
+    public long readUInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public long readInt64() throws IOException {
+      return readRawVarint64();
+    }
+
+    @Override
+    public int readInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public long readFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public boolean readBool() throws IOException {
+      return readRawVarint64() != 0;
+    }
+
+    @Override
+    public String readString() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+        byte[] bytes = new byte[size];
+        UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+        String result = new String(bytes, UTF_8);
+        currentByteBufferPos += size;
+        return result;
+      } else if (size > 0 && size <= remaining()) {
+        // TODO(yilunchong): To use an underlying bytes[] instead of allocating a new bytes[]
+        byte[] bytes = new byte[size];
+        readRawBytesTo(bytes, 0, size);
+        String result = new String(bytes, UTF_8);
+        return result;
+      }
+
+      if (size == 0) {
+        return "";
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
       throw InvalidProtocolBufferException.truncatedMessage();
     }
 
-    // Skipping more bytes than are in the buffer.  First skip what we have.
-    int pos = bufferSize - bufferPos;
-    bufferPos = bufferSize;
+    @Override
+    public String readStringRequireUtf8() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+        if (ENABLE_CUSTOM_UTF8_DECODE) {
+          final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos);
+          String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size);
+          currentByteBufferPos += size;
+          return result;
+        } else {
+          byte[] bytes = new byte[size];
+          UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+          if (!Utf8.isValidUtf8(bytes)) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          String result = new String(bytes, UTF_8);
+          currentByteBufferPos += size;
+          return result;
+        }
+      }
+      if (size >= 0 && size <= remaining()) {
+        byte[] bytes = new byte[size];
+        readRawBytesTo(bytes, 0, size);
+        if (ENABLE_CUSTOM_UTF8_DECODE) {
+          return Utf8.decodeUtf8(bytes, 0, size);
+        } else {
+          if (!Utf8.isValidUtf8(bytes)) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          String result = new String(bytes, UTF_8);
+          return result;
+        }
+      }
 
-    // Keep refilling the buffer until we get to the point we wanted to skip to.
-    // This has the side effect of ensuring the limits are updated correctly.
-    refillBuffer(1);
-    while (size - pos > bufferSize) {
-      pos += bufferSize;
-      bufferPos = bufferSize;
-      refillBuffer(1);
+      if (size == 0) {
+        return "";
+      }
+      if (size <= 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
     }
 
-    bufferPos = size - pos;
+    @Override
+    public void readGroup(
+        final int fieldNumber,
+        final MessageLite.Builder builder,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readGroup(
+        final int fieldNumber,
+        final Parser<T> parser,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+      --recursionDepth;
+      return result;
+    }
+
+    @Deprecated
+    @Override
+    public void readUnknownGroup(final int fieldNumber, final MessageLite.Builder builder)
+        throws IOException {
+      readGroup(fieldNumber, builder, ExtensionRegistryLite.getEmptyRegistry());
+    }
+
+    @Override
+    public void readMessage(
+        final MessageLite.Builder builder, final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      builder.mergeFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+    }
+
+
+    @Override
+    public <T extends MessageLite> T readMessage(
+        final Parser<T> parser, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      int length = readRawVarint32();
+      if (recursionDepth >= recursionLimit) {
+        throw InvalidProtocolBufferException.recursionLimitExceeded();
+      }
+      final int oldLimit = pushLimit(length);
+      ++recursionDepth;
+      T result = parser.parsePartialFrom(this, extensionRegistry);
+      checkLastTagWas(0);
+      --recursionDepth;
+      popLimit(oldLimit);
+      return result;
+    }
+
+    @Override
+    public ByteString readBytes() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
+        if (immutable && enableAliasing) {
+          final int idx = (int) (currentByteBufferPos - currentAddress);
+          final ByteString result = ByteString.wrap(slice(idx, idx + size));
+          currentByteBufferPos += size;
+          return result;
+        } else {
+          byte[] bytes;
+          bytes = new byte[size];
+          UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+          currentByteBufferPos += size;
+          return ByteString.wrap(bytes);
+        }
+      } else if (size > 0 && size <= remaining()) {
+        byte[] temp = new byte[size];
+        readRawBytesTo(temp, 0, size);
+        return ByteString.wrap(temp);
+      }
+
+      if (size == 0) {
+        return ByteString.EMPTY;
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public byte[] readByteArray() throws IOException {
+      return readRawBytes(readRawVarint32());
+    }
+
+    @Override
+    public ByteBuffer readByteBuffer() throws IOException {
+      final int size = readRawVarint32();
+      if (size > 0 && size <= currentRemaining()) {
+        if (!immutable && enableAliasing) {
+          currentByteBufferPos += size;
+          return slice(
+              (int) (currentByteBufferPos - currentAddress - size),
+              (int) (currentByteBufferPos - currentAddress));
+        } else {
+          byte[] bytes = new byte[size];
+          UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
+          currentByteBufferPos += size;
+          return ByteBuffer.wrap(bytes);
+        }
+      } else if (size > 0 && size <= remaining()) {
+        byte[] temp = new byte[size];
+        readRawBytesTo(temp, 0, size);
+        return ByteBuffer.wrap(temp);
+      }
+
+      if (size == 0) {
+        return EMPTY_BYTE_BUFFER;
+      }
+      if (size < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public int readUInt32() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readEnum() throws IOException {
+      return readRawVarint32();
+    }
+
+    @Override
+    public int readSFixed32() throws IOException {
+      return readRawLittleEndian32();
+    }
+
+    @Override
+    public long readSFixed64() throws IOException {
+      return readRawLittleEndian64();
+    }
+
+    @Override
+    public int readSInt32() throws IOException {
+      return decodeZigZag32(readRawVarint32());
+    }
+
+    @Override
+    public long readSInt64() throws IOException {
+      return decodeZigZag64(readRawVarint64());
+    }
+
+    @Override
+    public int readRawVarint32() throws IOException {
+      fastpath:
+      {
+        long tempPos = currentByteBufferPos;
+
+        if (currentByteBufferLimit == currentByteBufferPos) {
+          break fastpath;
+        }
+
+        int x;
+        if ((x = UnsafeUtil.getByte(tempPos++)) >= 0) {
+          currentByteBufferPos++;
+          return x;
+        } else if (currentByteBufferLimit - currentByteBufferPos < 10) {
+          break fastpath;
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+          x ^= (~0 << 7);
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+          x ^= (~0 << 7) ^ (~0 << 14);
+        } else if ((x ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+        } else {
+          int y = UnsafeUtil.getByte(tempPos++);
+          x ^= y << 28;
+          x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+          if (y < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0
+              && UnsafeUtil.getByte(tempPos++) < 0) {
+            break fastpath; // Will throw malformedVarint()
+          }
+        }
+        currentByteBufferPos = tempPos;
+        return x;
+      }
+      return (int) readRawVarint64SlowPath();
+    }
+
+    @Override
+    public long readRawVarint64() throws IOException {
+      fastpath:
+      {
+        long tempPos = currentByteBufferPos;
+
+        if (currentByteBufferLimit == currentByteBufferPos) {
+          break fastpath;
+        }
+
+        long x;
+        int y;
+        if ((y = UnsafeUtil.getByte(tempPos++)) >= 0) {
+          currentByteBufferPos++;
+          return y;
+        } else if (currentByteBufferLimit - currentByteBufferPos < 10) {
+          break fastpath;
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 7)) < 0) {
+          x = y ^ (~0 << 7);
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 14)) >= 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14));
+        } else if ((y ^= (UnsafeUtil.getByte(tempPos++) << 21)) < 0) {
+          x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+        } else if ((x = y ^ ((long) UnsafeUtil.getByte(tempPos++) << 28)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 35)) < 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 42)) >= 0L) {
+          x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+        } else if ((x ^= ((long) UnsafeUtil.getByte(tempPos++) << 49)) < 0L) {
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49);
+        } else {
+          x ^= ((long) UnsafeUtil.getByte(tempPos++) << 56);
+          x ^=
+              (~0L << 7)
+                  ^ (~0L << 14)
+                  ^ (~0L << 21)
+                  ^ (~0L << 28)
+                  ^ (~0L << 35)
+                  ^ (~0L << 42)
+                  ^ (~0L << 49)
+                  ^ (~0L << 56);
+          if (x < 0L) {
+            if (UnsafeUtil.getByte(tempPos++) < 0L) {
+              break fastpath; // Will throw malformedVarint()
+            }
+          }
+        }
+        currentByteBufferPos = tempPos;
+        return x;
+      }
+      return readRawVarint64SlowPath();
+    }
+
+    @Override
+    long readRawVarint64SlowPath() throws IOException {
+      long result = 0;
+      for (int shift = 0; shift < 64; shift += 7) {
+        final byte b = readRawByte();
+        result |= (long) (b & 0x7F) << shift;
+        if ((b & 0x80) == 0) {
+          return result;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    @Override
+    public int readRawLittleEndian32() throws IOException {
+      if (currentRemaining() >= FIXED32_SIZE) {
+        long tempPos = currentByteBufferPos;
+        currentByteBufferPos += FIXED32_SIZE;
+        return (((UnsafeUtil.getByte(tempPos) & 0xff))
+            | ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8)
+            | ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16)
+            | ((UnsafeUtil.getByte(tempPos + 3) & 0xff) << 24));
+      }
+      return ((readRawByte() & 0xff)
+          | ((readRawByte() & 0xff) << 8)
+          | ((readRawByte() & 0xff) << 16)
+          | ((readRawByte() & 0xff) << 24));
+    }
+
+    @Override
+    public long readRawLittleEndian64() throws IOException {
+      if (currentRemaining() >= FIXED64_SIZE) {
+        long tempPos = currentByteBufferPos;
+        currentByteBufferPos += FIXED64_SIZE;
+        return (((UnsafeUtil.getByte(tempPos) & 0xffL))
+            | ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8)
+            | ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16)
+            | ((UnsafeUtil.getByte(tempPos + 3) & 0xffL) << 24)
+            | ((UnsafeUtil.getByte(tempPos + 4) & 0xffL) << 32)
+            | ((UnsafeUtil.getByte(tempPos + 5) & 0xffL) << 40)
+            | ((UnsafeUtil.getByte(tempPos + 6) & 0xffL) << 48)
+            | ((UnsafeUtil.getByte(tempPos + 7) & 0xffL) << 56));
+      }
+      return ((readRawByte() & 0xffL)
+          | ((readRawByte() & 0xffL) << 8)
+          | ((readRawByte() & 0xffL) << 16)
+          | ((readRawByte() & 0xffL) << 24)
+          | ((readRawByte() & 0xffL) << 32)
+          | ((readRawByte() & 0xffL) << 40)
+          | ((readRawByte() & 0xffL) << 48)
+          | ((readRawByte() & 0xffL) << 56));
+    }
+
+    @Override
+    public void enableAliasing(boolean enabled) {
+      this.enableAliasing = enabled;
+    }
+
+    @Override
+    public void resetSizeCounter() {
+      startOffset = (int) (totalBytesRead + currentByteBufferPos - currentByteBufferStartPos);
+    }
+
+    @Override
+    public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+      if (byteLimit < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      byteLimit += getTotalBytesRead();
+      final int oldLimit = currentLimit;
+      if (byteLimit > oldLimit) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      currentLimit = byteLimit;
+
+      recomputeBufferSizeAfterLimit();
+
+      return oldLimit;
+    }
+
+    private void recomputeBufferSizeAfterLimit() {
+      totalBufferSize += bufferSizeAfterCurrentLimit;
+      final int bufferEnd = totalBufferSize - startOffset;
+      if (bufferEnd > currentLimit) {
+        // Limit is in current buffer.
+        bufferSizeAfterCurrentLimit = bufferEnd - currentLimit;
+        totalBufferSize -= bufferSizeAfterCurrentLimit;
+      } else {
+        bufferSizeAfterCurrentLimit = 0;
+      }
+    }
+
+    @Override
+    public void popLimit(final int oldLimit) {
+      currentLimit = oldLimit;
+      recomputeBufferSizeAfterLimit();
+    }
+
+    @Override
+    public int getBytesUntilLimit() {
+      if (currentLimit == Integer.MAX_VALUE) {
+        return -1;
+      }
+
+      return currentLimit - getTotalBytesRead();
+    }
+
+    @Override
+    public boolean isAtEnd() throws IOException {
+      return totalBytesRead + currentByteBufferPos - currentByteBufferStartPos == totalBufferSize;
+    }
+
+    @Override
+    public int getTotalBytesRead() {
+      return (int)
+          (totalBytesRead - startOffset + currentByteBufferPos - currentByteBufferStartPos);
+    }
+
+    @Override
+    public byte readRawByte() throws IOException {
+      if (currentRemaining() == 0) {
+        getNextByteBuffer();
+      }
+      return UnsafeUtil.getByte(currentByteBufferPos++);
+    }
+
+    @Override
+    public byte[] readRawBytes(final int length) throws IOException {
+      if (length >= 0 && length <= currentRemaining()) {
+        byte[] bytes = new byte[length];
+        UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, length);
+        currentByteBufferPos += length;
+        return bytes;
+      }
+      if (length >= 0 && length <= remaining()) {
+        byte[] bytes = new byte[length];
+        readRawBytesTo(bytes, 0, length);
+        return bytes;
+      }
+
+      if (length <= 0) {
+        if (length == 0) {
+          return EMPTY_BYTE_ARRAY;
+        } else {
+          throw InvalidProtocolBufferException.negativeSize();
+        }
+      }
+
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    /**
+     * Try to get raw bytes from {@code input} with the size of {@code length} and copy to {@code
+     * bytes} array. If the size is bigger than the number of remaining bytes in the input, then
+     * throw {@code truncatedMessage} exception.
+     *
+     * @param bytes
+     * @param offset
+     * @param length
+     * @throws IOException
+     */
+    private void readRawBytesTo(byte[] bytes, int offset, final int length) throws IOException {
+      if (length >= 0 && length <= remaining()) {
+        int l = length;
+        while (l > 0) {
+          if (currentRemaining() == 0) {
+            getNextByteBuffer();
+          }
+          int bytesToCopy = Math.min(l, (int) currentRemaining());
+          UnsafeUtil.copyMemory(currentByteBufferPos, bytes, length - l + offset, bytesToCopy);
+          l -= bytesToCopy;
+          currentByteBufferPos += bytesToCopy;
+        }
+        return;
+      }
+
+      if (length <= 0) {
+        if (length == 0) {
+          return;
+        } else {
+          throw InvalidProtocolBufferException.negativeSize();
+        }
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    @Override
+    public void skipRawBytes(final int length) throws IOException {
+      if (length >= 0
+          && length
+              <= (totalBufferSize
+                  - totalBytesRead
+                  - currentByteBufferPos
+                  + currentByteBufferStartPos)) {
+        // We have all the bytes we need already.
+        int l = length;
+        while (l > 0) {
+          if (currentRemaining() == 0) {
+            getNextByteBuffer();
+          }
+          int rl = Math.min(l, (int) currentRemaining());
+          l -= rl;
+          currentByteBufferPos += rl;
+        }
+        return;
+      }
+
+      if (length < 0) {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    // TODO: optimize to fastpath
+    private void skipRawVarint() throws IOException {
+      for (int i = 0; i < MAX_VARINT_SIZE; i++) {
+        if (readRawByte() >= 0) {
+          return;
+        }
+      }
+      throw InvalidProtocolBufferException.malformedVarint();
+    }
+
+    /**
+     * Try to get the number of remaining bytes in {@code input}.
+     *
+     * @return the number of remaining bytes in {@code input}.
+     */
+    private int remaining() {
+      return (int)
+          (totalBufferSize - totalBytesRead - currentByteBufferPos + currentByteBufferStartPos);
+    }
+
+    /**
+     * Try to get the number of remaining bytes in {@code currentByteBuffer}.
+     *
+     * @return the number of remaining bytes in {@code currentByteBuffer}
+     */
+    private long currentRemaining() {
+      return (currentByteBufferLimit - currentByteBufferPos);
+    }
+
+    private ByteBuffer slice(int begin, int end) throws IOException {
+      int prevPos = currentByteBuffer.position();
+      int prevLimit = currentByteBuffer.limit();
+      try {
+        currentByteBuffer.position(begin);
+        currentByteBuffer.limit(end);
+        return currentByteBuffer.slice();
+      } catch (IllegalArgumentException e) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      } finally {
+        currentByteBuffer.position(prevPos);
+        currentByteBuffer.limit(prevLimit);
+      }
+    }
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index d8ebad2..7b1ac65 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -30,11 +30,17 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Utf8.UnpairedSurrogateException;
+import static com.google.protobuf.WireFormat.FIXED32_SIZE;
+import static com.google.protobuf.WireFormat.FIXED64_SIZE;
+import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
+import static java.lang.Math.max;
 
+import com.google.protobuf.Utf8.UnpairedSurrogateException;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -49,20 +55,16 @@
  * you are writing some other format of your own design, use the latter.
  *
  * <p>This class is totally unsynchronized.
- *
- * @author kneton@google.com Kenton Varda
  */
-public final class CodedOutputStream {
-
+public abstract class CodedOutputStream extends ByteOutput {
   private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
+  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
 
-  // TODO(dweis): Consider migrating to a ByteBuffer.
-  private final byte[] buffer;
-  private final int limit;
-  private int position;
-  private int totalBytesWritten = 0;
-
-  private final OutputStream output;
+  /**
+   * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
+   */
+  @Deprecated
+  public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
 
   /**
    * The buffer size used in {@link #newInstance(OutputStream)}.
@@ -77,40 +79,33 @@
    *         CodedOutputStream.
    */
   static int computePreferredBufferSize(int dataLength) {
-    if (dataLength > DEFAULT_BUFFER_SIZE) return DEFAULT_BUFFER_SIZE;
+    if (dataLength > DEFAULT_BUFFER_SIZE) {
+      return DEFAULT_BUFFER_SIZE;
+    }
     return dataLength;
   }
 
-  private CodedOutputStream(final byte[] buffer, final int offset,
-                            final int length) {
-    output = null;
-    this.buffer = buffer;
-    position = offset;
-    limit = offset + length;
-  }
-
-  private CodedOutputStream(final OutputStream output, final byte[] buffer) {
-    this.output = output;
-    this.buffer = buffer;
-    position = 0;
-    limit = buffer.length;
-  }
-
   /**
-   * Create a new {@code CodedOutputStream} wrapping the given
-   * {@code OutputStream}.
+   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}.
+   *
+   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+   * difficult to debug.
    */
   public static CodedOutputStream newInstance(final OutputStream output) {
     return newInstance(output, DEFAULT_BUFFER_SIZE);
   }
 
   /**
-   * Create a new {@code CodedOutputStream} wrapping the given
-   * {@code OutputStream} with a given buffer size.
+   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given
+   * buffer size.
+   *
+   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+   * difficult to debug.
    */
-  public static CodedOutputStream newInstance(final OutputStream output,
-      final int bufferSize) {
-    return new CodedOutputStream(output, new byte[bufferSize]);
+  public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) {
+    return new OutputStreamEncoder(output, bufferSize);
   }
 
   /**
@@ -131,149 +126,197 @@
    * array is faster than writing to an {@code OutputStream}.  See also
    * {@link ByteString#newCodedBuilder}.
    */
-  public static CodedOutputStream newInstance(final byte[] flatArray,
-                                              final int offset,
-                                              final int length) {
-    return new CodedOutputStream(flatArray, offset, length);
+  public static CodedOutputStream newInstance(
+      final byte[] flatArray, final int offset, final int length) {
+    return new ArrayEncoder(flatArray, offset, length);
+  }
+
+  /** Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. */
+  public static CodedOutputStream newInstance(ByteBuffer buffer) {
+    if (buffer.hasArray()) {
+      return new HeapNioEncoder(buffer);
+    }
+    if (buffer.isDirect() && !buffer.isReadOnly()) {
+      return UnsafeDirectNioEncoder.isSupported()
+          ? newUnsafeInstance(buffer)
+          : newSafeInstance(buffer);
+    }
+    throw new IllegalArgumentException("ByteBuffer is read-only");
+  }
+
+  /** For testing purposes only. */
+  static CodedOutputStream newUnsafeInstance(ByteBuffer buffer) {
+    return new UnsafeDirectNioEncoder(buffer);
+  }
+
+  /** For testing purposes only. */
+  static CodedOutputStream newSafeInstance(ByteBuffer buffer) {
+    return new SafeDirectNioEncoder(buffer);
   }
 
   /**
-   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+   * Configures serialization to be deterministic.
+   *
+   * <p>The deterministic serialization guarantees that for a given binary, equal (defined by the
+   * {@code equals()} methods in protos) messages will always be serialized to the same bytes. This
+   * implies:
+   *
+   * <ul>
+   * <li>repeated serialization of a message will return the same bytes
+   * <li>different processes of the same binary (which may be executing on different machines) will
+   *     serialize equal messages to the same bytes.
+   * </ul>
+   *
+   * <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable
+   * across different builds with schema changes due to unknown fields. Users who need canonical
+   * serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define
+   * their own canonicalization specification and implement the serializer using reflection APIs
+   * rather than relying on this API.
+   *
+   * <p> Once set, the serializer will:  (Note this is an implementation detail and may subject to
+   * change in the future)
+   *
+   * <ul>
+   * <li> sort map entries by keys in lexicographical order or numerical order. Note: For string
+   *     keys, the order is based on comparing the Unicode value of each character in the strings.
+   *     The order may be different from the deterministic serialization in other languages where
+   *     maps are sorted on the lexicographical order of the UTF8 encoded keys.
+   * </ul>
    */
-  public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
-    return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE);
+  public void useDeterministicSerialization() {
+    serializationDeterministic = true;
   }
 
+  boolean isSerializationDeterministic() {
+    return serializationDeterministic;
+  }
+  private boolean serializationDeterministic;
+
   /**
-   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
+   * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
+   *
+   * @deprecated the size parameter is no longer used since use of an internal buffer is useless
+   * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
+   * instead.
    */
+  @Deprecated
   public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
-      int bufferSize) {
-    return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize);
+      @SuppressWarnings("unused") int unused) {
+    return newInstance(byteBuffer);
   }
 
-  private static class ByteBufferOutputStream extends OutputStream {
-    private final ByteBuffer byteBuffer;
-    public ByteBufferOutputStream(ByteBuffer byteBuffer) {
-      this.byteBuffer = byteBuffer;
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}.
+   *
+   * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+   * so may result in corrupted data, which would be difficult to debug.
+   *
+   * @param byteOutput the output target for encoded bytes.
+   * @param bufferSize the size of the internal scratch buffer to be used for string encoding.
+   * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
+   * string.
+   */
+  static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) {
+    if (bufferSize < 0) {
+      throw new IllegalArgumentException("bufferSize must be positive");
     }
 
-    @Override
-    public void write(int b) throws IOException {
-      byteBuffer.put((byte) b);
-    }
+    return new ByteOutputEncoder(byteOutput, bufferSize);
+  }
 
-    @Override
-    public void write(byte[] data, int offset, int length) throws IOException {
-      byteBuffer.put(data, offset, length);
-    }
+  // Disallow construction outside of this class.
+  private CodedOutputStream() {
   }
 
   // -----------------------------------------------------------------
 
-  /** Write a {@code double} field, including tag, to the stream. */
-  public void writeDouble(final int fieldNumber, final double value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeDoubleNoTag(value);
-  }
-
-  /** Write a {@code float} field, including tag, to the stream. */
-  public void writeFloat(final int fieldNumber, final float value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeFloatNoTag(value);
-  }
-
-  /** Write a {@code uint64} field, including tag, to the stream. */
-  public void writeUInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeUInt64NoTag(value);
-  }
-
-  /** Write an {@code int64} field, including tag, to the stream. */
-  public void writeInt64(final int fieldNumber, final long value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeInt64NoTag(value);
-  }
+  /** Encode and write a tag. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeTag(int fieldNumber, int wireType) throws IOException;
 
   /** Write an {@code int32} field, including tag, to the stream. */
-  public void writeInt32(final int fieldNumber, final int value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeInt32NoTag(value);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeInt32(int fieldNumber, int value) throws IOException;
 
-  /** Write a {@code fixed64} field, including tag, to the stream. */
-  public void writeFixed64(final int fieldNumber, final long value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeFixed64NoTag(value);
+  /** Write a {@code uint32} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt32(int fieldNumber, int value) throws IOException;
+
+  /** Write a {@code sint32} field, including tag, to the stream. */
+  public final void writeSInt32(final int fieldNumber, final int value) throws IOException {
+    writeUInt32(fieldNumber, encodeZigZag32(value));
   }
 
   /** Write a {@code fixed32} field, including tag, to the stream. */
-  public void writeFixed32(final int fieldNumber, final int value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeFixed32NoTag(value);
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed32(int fieldNumber, int value) throws IOException;
+
+  /** Write an {@code sfixed32} field, including tag, to the stream. */
+  public final void writeSFixed32(final int fieldNumber, final int value) throws IOException {
+    writeFixed32(fieldNumber, value);
+  }
+
+  /** Write an {@code int64} field, including tag, to the stream. */
+  public final void writeInt64(final int fieldNumber, final long value) throws IOException {
+    writeUInt64(fieldNumber, value);
+  }
+
+  /** Write a {@code uint64} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt64(int fieldNumber, long value) throws IOException;
+
+  /** Write an {@code sint64} field, including tag, to the stream. */
+  public final void writeSInt64(final int fieldNumber, final long value) throws IOException {
+    writeUInt64(fieldNumber, encodeZigZag64(value));
+  }
+
+  /** Write a {@code fixed64} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed64(int fieldNumber, long value) throws IOException;
+
+  /** Write an {@code sfixed64} field, including tag, to the stream. */
+  public final void writeSFixed64(final int fieldNumber, final long value) throws IOException {
+    writeFixed64(fieldNumber, value);
+  }
+
+  /** Write a {@code float} field, including tag, to the stream. */
+  public final void writeFloat(final int fieldNumber, final float value) throws IOException {
+    writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
+  }
+
+  /** Write a {@code double} field, including tag, to the stream. */
+  public final void writeDouble(final int fieldNumber, final double value) throws IOException {
+    writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
   }
 
   /** Write a {@code bool} field, including tag, to the stream. */
-  public void writeBool(final int fieldNumber, final boolean value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeBoolNoTag(value);
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
+
+  /**
+   * Write an enum field, including tag, to the stream. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public final void writeEnum(final int fieldNumber, final int value) throws IOException {
+    writeInt32(fieldNumber, value);
   }
 
   /** Write a {@code string} field, including tag, to the stream. */
-  public void writeString(final int fieldNumber, final String value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeStringNoTag(value);
-  }
-
-  /** Write a {@code group} field, including tag, to the stream. */
-  public void writeGroup(final int fieldNumber, final MessageLite value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
-    writeGroupNoTag(value);
-    writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
-  }
-
-
-  /** Write an embedded message field, including tag, to the stream. */
-  public void writeMessage(final int fieldNumber, final MessageLite value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeMessageNoTag(value);
-  }
-
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeString(int fieldNumber, String value) throws IOException;
 
   /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeBytes(final int fieldNumber, final ByteString value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeBytesNoTag(value);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException;
 
   /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeByteArray(final int fieldNumber, final byte[] value)
-                             throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteArrayNoTag(value);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException;
 
   /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeByteArray(final int fieldNumber,
-                             final byte[] value,
-                             final int offset,
-                             final int length)
-                             throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteArrayNoTag(value, offset, length);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
+      throws IOException;
 
   /**
    * Write a {@code bytes} field, including tag, to the stream.
@@ -285,326 +328,184 @@
    * of a ByteBuffer, you can call
    * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
    */
-  public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
-      throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteBufferNoTag(value);
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
+
+  /**
+   * Write a single byte.
+   */
+  public final void writeRawByte(final byte value) throws IOException {
+    write(value);
   }
 
-  /** Write a {@code uint32} field, including tag, to the stream. */
-  public void writeUInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeUInt32NoTag(value);
+  /** Write a single byte, represented by an integer value. */
+  public final void writeRawByte(final int value) throws IOException {
+    write((byte) value);
+  }
+
+  /** Write an array of bytes. */
+  public final void writeRawBytes(final byte[] value) throws IOException {
+    write(value, 0, value.length);
   }
 
   /**
-   * Write an enum field, including tag, to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
+   * Write part of an array of bytes.
    */
-  public void writeEnum(final int fieldNumber, final int value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeEnumNoTag(value);
+  public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException {
+    write(value, offset, length);
   }
 
-  /** Write an {@code sfixed32} field, including tag, to the stream. */
-  public void writeSFixed32(final int fieldNumber, final int value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeSFixed32NoTag(value);
+  /** Write a byte string. */
+  public final void writeRawBytes(final ByteString value) throws IOException {
+    value.writeTo(this);
   }
 
-  /** Write an {@code sfixed64} field, including tag, to the stream. */
-  public void writeSFixed64(final int fieldNumber, final long value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeSFixed64NoTag(value);
-  }
+  /**
+   * Write a ByteBuffer. This method will write all content of the ByteBuffer
+   * regardless of the current position and limit (i.e., the number of bytes
+   * to be written is value.capacity(), not value.remaining()). Furthermore,
+   * this method doesn't alter the state of the passed-in ByteBuffer. Its
+   * position, limit, mark, etc. will remain unchanged. If you only want to
+   * write the remaining bytes of a ByteBuffer, you can call
+   * {@code writeRawBytes(byteBuffer.slice())}.
+   */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
 
-  /** Write an {@code sint32} field, including tag, to the stream. */
-  public void writeSInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeSInt32NoTag(value);
-  }
+  /** Write an embedded message field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessage(final int fieldNumber, final MessageLite value)
+      throws IOException;
 
-  /** Write an {@code sint64} field, including tag, to the stream. */
-  public void writeSInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeSInt64NoTag(value);
-  }
 
   /**
    * Write a MessageSet extension field to the stream.  For historical reasons,
    * the wire format differs from normal fields.
    */
-  public void writeMessageSetExtension(final int fieldNumber,
-                                       final MessageLite value)
-                                       throws IOException {
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
-    writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
-    writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+      throws IOException;
 
   /**
    * Write an unparsed MessageSet extension field to the stream.  For
    * historical reasons, the wire format differs from normal fields.
    */
-  public void writeRawMessageSetExtension(final int fieldNumber,
-                                          final ByteString value)
-                                          throws IOException {
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
-    writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
-    writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+      throws IOException;
 
   // -----------------------------------------------------------------
 
-  /** Write a {@code double} field to the stream. */
-  public void writeDoubleNoTag(final double value) throws IOException {
-    writeRawLittleEndian64(Double.doubleToRawLongBits(value));
-  }
-
-  /** Write a {@code float} field to the stream. */
-  public void writeFloatNoTag(final float value) throws IOException {
-    writeRawLittleEndian32(Float.floatToRawIntBits(value));
-  }
-
-  /** Write a {@code uint64} field to the stream. */
-  public void writeUInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
-  /** Write an {@code int64} field to the stream. */
-  public void writeInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
   /** Write an {@code int32} field to the stream. */
-  public void writeInt32NoTag(final int value) throws IOException {
-    if (value >= 0) {
-      writeRawVarint32(value);
-    } else {
-      // Must sign-extend.
-      writeRawVarint64(value);
-    }
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeInt32NoTag(final int value) throws IOException;
 
-  /** Write a {@code fixed64} field to the stream. */
-  public void writeFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
+  /** Write a {@code uint32} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt32NoTag(int value) throws IOException;
+
+  /** Write a {@code sint32} field to the stream. */
+  public final void writeSInt32NoTag(final int value) throws IOException {
+    writeUInt32NoTag(encodeZigZag32(value));
   }
 
   /** Write a {@code fixed32} field to the stream. */
-  public void writeFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed32NoTag(int value) throws IOException;
+
+  /** Write a {@code sfixed32} field to the stream. */
+  public final void writeSFixed32NoTag(final int value) throws IOException {
+    writeFixed32NoTag(value);
+  }
+
+  /** Write an {@code int64} field to the stream. */
+  public final void writeInt64NoTag(final long value) throws IOException {
+    writeUInt64NoTag(value);
+  }
+
+  /** Write a {@code uint64} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt64NoTag(long value) throws IOException;
+
+  /** Write a {@code sint64} field to the stream. */
+  public final void writeSInt64NoTag(final long value) throws IOException {
+    writeUInt64NoTag(encodeZigZag64(value));
+  }
+
+  /** Write a {@code fixed64} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed64NoTag(long value) throws IOException;
+
+  /** Write a {@code sfixed64} field to the stream. */
+  public final void writeSFixed64NoTag(final long value) throws IOException {
+    writeFixed64NoTag(value);
+  }
+
+  /** Write a {@code float} field to the stream. */
+  public final void writeFloatNoTag(final float value) throws IOException {
+    writeFixed32NoTag(Float.floatToRawIntBits(value));
+  }
+
+  /** Write a {@code double} field to the stream. */
+  public final void writeDoubleNoTag(final double value) throws IOException {
+    writeFixed64NoTag(Double.doubleToRawLongBits(value));
   }
 
   /** Write a {@code bool} field to the stream. */
-  public void writeBoolNoTag(final boolean value) throws IOException {
-    writeRawByte(value ? 1 : 0);
+  public final void writeBoolNoTag(final boolean value) throws IOException {
+    write((byte) (value ? 1 : 0));
+  }
+
+  /**
+   * Write an enum field to the stream. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public final void writeEnumNoTag(final int value) throws IOException {
+    writeInt32NoTag(value);
   }
 
   /** Write a {@code string} field to the stream. */
   // TODO(dweis): Document behavior on ill-formed UTF-16 input.
-  public void writeStringNoTag(final String value) throws IOException {
-    try {
-      efficientWriteStringNoTag(value);
-    } catch (UnpairedSurrogateException e) {
-      logger.log(Level.WARNING,
-          "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e);
-      inefficientWriteStringNoTag(value);
-    }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeStringNoTag(String value) throws IOException;
+
+  /** Write a {@code bytes} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBytesNoTag(final ByteString value) throws IOException;
+
+  /** Write a {@code bytes} field to the stream. */
+  public final void writeByteArrayNoTag(final byte[] value) throws IOException {
+    writeByteArrayNoTag(value, 0, value.length);
   }
 
-  /** Write a {@code string} field to the stream. */
-  private void inefficientWriteStringNoTag(final String value) throws IOException {
-    // Unfortunately there does not appear to be any way to tell Java to encode
-    // UTF-8 directly into our buffer, so we have to let it create its own byte
-    // array and then copy.
-    // TODO(dweis): Consider using nio Charset methods instead.
-    final byte[] bytes = value.getBytes(Internal.UTF_8);
-    writeRawVarint32(bytes.length);
-    writeRawBytes(bytes);
-  }
-
-  /**
-   * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed,
-   * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the
-   * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}.
-   *
-   * @param value the string to write to the stream
-   *
-   * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16.
-   */
-  private void efficientWriteStringNoTag(final String value) throws IOException {
-    // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
-    // and at most 3 times of it. We take advantage of this in both branches below.
-    final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
-    final int maxLengthVarIntSize = computeRawVarint32Size(maxLength);
-
-    // If we are streaming and the potential length is too big to fit in our buffer, we take the
-    // slower path. Otherwise, we're good to try the fast path.
-    if (output != null && maxLengthVarIntSize + maxLength > limit - position) {
-      // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
-      // does the same internally and then does *another copy* to return a byte[] of exactly the
-      // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
-      // UTF-8 encoded bytes.
-      final byte[] encodedBytes = new byte[maxLength];
-      int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
-      writeRawVarint32(actualLength);
-      writeRawBytes(encodedBytes, 0, actualLength);
-    } else {
-      // Optimize for the case where we know this length results in a constant varint length as this
-      // saves a pass for measuring the length of the string.
-      final int minLengthVarIntSize = computeRawVarint32Size(value.length());
-      int oldPosition = position;
-      final int length;
-      try {
-        if (minLengthVarIntSize == maxLengthVarIntSize) {
-          position = oldPosition + minLengthVarIntSize;
-          int newPosition = Utf8.encode(value, buffer, position, limit - position);
-          // Since this class is stateful and tracks the position, we rewind and store the state,
-          // prepend the length, then reset it back to the end of the string.
-          position = oldPosition;
-          length = newPosition - oldPosition - minLengthVarIntSize;
-          writeRawVarint32(length);
-          position = newPosition;
-        } else {
-          length = Utf8.encodedLength(value);
-          writeRawVarint32(length);
-          position = Utf8.encode(value, buffer, position, limit - position);
-        }
-      } catch (UnpairedSurrogateException e) {
-        // Be extra careful and restore the original position for retrying the write with the less
-        // efficient path.
-        position = oldPosition;
-        throw e;
-      } catch (ArrayIndexOutOfBoundsException e) {
-        throw new OutOfSpaceException(e);
-      }
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Write a {@code group} field to the stream. */
-  public void writeGroupNoTag(final MessageLite value) throws IOException {
-    value.writeTo(this);
-  }
-
-
   /** Write an embedded message field to the stream. */
-  public void writeMessageNoTag(final MessageLite value) throws IOException {
-    writeRawVarint32(value.getSerializedSize());
-    value.writeTo(this);
-  }
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
 
 
-  /** Write a {@code bytes} field to the stream. */
-  public void writeBytesNoTag(final ByteString value) throws IOException {
-    writeRawVarint32(value.size());
-    writeRawBytes(value);
-  }
+  //=================================================================
 
-  /** Write a {@code bytes} field to the stream. */
-  public void writeByteArrayNoTag(final byte[] value) throws IOException {
-    writeRawVarint32(value.length);
-    writeRawBytes(value);
-  }
+  @ExperimentalApi
+  @Override
+  public abstract void write(byte value) throws IOException;
 
-  /** Write a {@code bytes} field to the stream. */
-  public void writeByteArrayNoTag(final byte[] value,
-                                  final int offset,
-                                  final int length) throws IOException {
-    writeRawVarint32(length);
-    writeRawBytes(value, offset, length);
-  }
+  @ExperimentalApi
+  @Override
+  public abstract void write(byte[] value, int offset, int length) throws IOException;
 
-  /**
-   * Write a {@code bytes} field to the stream.  This method will write all
-   * content of the ByteBuffer regardless of the current position and limit
-   * (i.e., the number of bytes to be written is value.capacity(), not
-   * value.remaining()). Furthermore, this method doesn't alter the state of
-   * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain
-   * unchanged. If you only want to write the remaining bytes of a ByteBuffer,
-   * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}.
-   */
-  public void writeByteBufferNoTag(final ByteBuffer value) throws IOException {
-    writeRawVarint32(value.capacity());
-    writeRawBytes(value);
-  }
+  @ExperimentalApi
+  @Override
+  public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
 
-  /** Write a {@code uint32} field to the stream. */
-  public void writeUInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(value);
-  }
+  @Override
+  public abstract void write(ByteBuffer value) throws IOException;
 
-  /**
-   * Write an enum field to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
-   */
-  public void writeEnumNoTag(final int value) throws IOException {
-    writeInt32NoTag(value);
-  }
-
-  /** Write an {@code sfixed32} field to the stream. */
-  public void writeSFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
-  }
-
-  /** Write an {@code sfixed64} field to the stream. */
-  public void writeSFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
-  }
-
-  /** Write an {@code sint32} field to the stream. */
-  public void writeSInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(encodeZigZag32(value));
-  }
-
-  /** Write an {@code sint64} field to the stream. */
-  public void writeSInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(encodeZigZag64(value));
-  }
+  @ExperimentalApi
+  @Override
+  public abstract void writeLazy(ByteBuffer value) throws IOException;
 
   // =================================================================
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSize(final int fieldNumber,
-                                      final double value) {
-    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSize(final int fieldNumber, final float value) {
-    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
-  }
+  // =================================================================
 
   /**
    * Compute the number of bytes that would be needed to encode an
@@ -616,96 +517,6 @@
 
   /**
    * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field, including tag.
-   */
-  public static int computeFixed64Size(final int fieldNumber,
-                                       final long value) {
-    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed32} field, including tag.
-   */
-  public static int computeFixed32Size(final int fieldNumber,
-                                       final int value) {
-    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bool} field, including tag.
-   */
-  public static int computeBoolSize(final int fieldNumber,
-                                    final boolean value) {
-    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code string} field, including tag.
-   */
-  public static int computeStringSize(final int fieldNumber,
-                                      final String value) {
-    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field, including tag.
-   */
-  public static int computeGroupSize(final int fieldNumber,
-                                     final MessageLite value) {
-    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * embedded message field, including tag.
-   */
-  public static int computeMessageSize(final int fieldNumber,
-                                       final MessageLite value) {
-    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeBytesSize(final int fieldNumber,
-                                     final ByteString value) {
-    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeByteArraySize(final int fieldNumber,
-                                         final byte[] value) {
-    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeByteBufferSize(final int fieldNumber,
-                                         final ByteBuffer value) {
-    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * embedded message in lazy field, including tag.
-   */
-  public static int computeLazyFieldSize(final int fieldNumber,
-                                         final LazyFieldLite value) {
-    return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
    * {@code uint32} field, including tag.
    */
   public static int computeUInt32Size(final int fieldNumber, final int value) {
@@ -714,37 +525,42 @@
 
   /**
    * Compute the number of bytes that would be needed to encode an
-   * enum field, including tag.  Caller is responsible for converting the
-   * enum value to its numeric value.
+   * {@code sint32} field, including tag.
    */
-  public static int computeEnumSize(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+  public static int computeSInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field, including tag.
+   */
+  public static int computeFixed32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
   }
 
   /**
    * Compute the number of bytes that would be needed to encode an
    * {@code sfixed32} field, including tag.
    */
-  public static int computeSFixed32Size(final int fieldNumber,
-                                        final int value) {
+  public static int computeSFixed32Size(final int fieldNumber, final int value) {
     return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
   }
 
   /**
    * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field, including tag.
+   * {@code int64} field, including tag.
    */
-  public static int computeSFixed64Size(final int fieldNumber,
-                                        final long value) {
-    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+  public static int computeInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
   }
 
   /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field, including tag.
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
    */
-  public static int computeSInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+  public static int computeUInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
   }
 
   /**
@@ -757,14 +573,111 @@
 
   /**
    * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field, including tag.
+   */
+  public static int computeFixed64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field, including tag.
+   */
+  public static int computeSFixed64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSize(final int fieldNumber, final float value) {
+    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSize(final int fieldNumber, final double value) {
+    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field, including tag.
+   */
+  public static int computeBoolSize(final int fieldNumber, final boolean value) {
+    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * enum field, including tag. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public static int computeEnumSize(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field, including tag.
+   */
+  public static int computeStringSize(final int fieldNumber, final String value) {
+    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeBytesSize(final int fieldNumber, final ByteString value) {
+    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteArraySize(final int fieldNumber, final byte[] value) {
+    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) {
+    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message in lazy field, including tag.
+   */
+  public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) {
+    return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message field, including tag.
+   */
+  public static int computeMessageSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+  }
+
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
    * MessageSet extension to the stream.  For historical reasons,
    * the wire format differs from normal fields.
    */
-  public static int computeMessageSetExtensionSize(
-      final int fieldNumber, final MessageLite value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+  public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
   }
 
   /**
@@ -774,9 +687,9 @@
    */
   public static int computeRawMessageSetExtensionSize(
       final int fieldNumber, final ByteString value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
   }
 
   /**
@@ -786,43 +699,16 @@
    */
   public static int computeLazyFieldMessageSetExtensionSize(
       final int fieldNumber, final LazyFieldLite value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
   }
 
   // -----------------------------------------------------------------
 
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSizeNoTag(final double value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSizeNoTag(final float value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
+  /** Compute the number of bytes that would be needed to encode a tag. */
+  public static int computeTagSize(final int fieldNumber) {
+    return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0));
   }
 
   /**
@@ -831,38 +717,149 @@
    */
   public static int computeInt32SizeNoTag(final int value) {
     if (value >= 0) {
-      return computeRawVarint32Size(value);
+      return computeUInt32SizeNoTag(value);
     } else {
       // Must sign-extend.
-      return 10;
+      return MAX_VARINT_SIZE;
     }
   }
 
   /**
    * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field.
+   * {@code uint32} field.
    */
-  public static int computeFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
+  public static int computeUInt32SizeNoTag(final int value) {
+    if ((value & (~0 <<  7)) == 0) {
+      return 1;
+    }
+    if ((value & (~0 << 14)) == 0) {
+      return 2;
+    }
+    if ((value & (~0 << 21)) == 0) {
+      return 3;
+    }
+    if ((value & (~0 << 28)) == 0) {
+      return 4;
+    }
+    return 5;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field.
+   */
+  public static int computeSInt32SizeNoTag(final int value) {
+    return computeUInt32SizeNoTag(encodeZigZag32(value));
   }
 
   /**
    * Compute the number of bytes that would be needed to encode a
    * {@code fixed32} field.
    */
-  public static int computeFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
+  public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+    return FIXED32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field.
+   */
+  public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+    return FIXED32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64SizeNoTag(final long value) {
+    return computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64SizeNoTag(long value) {
+    // handle two popular special cases up front ...
+    if ((value & (~0L << 7)) == 0L) {
+      return 1;
+    }
+    if (value < 0L) {
+      return 10;
+    }
+    // ... leaving us with 8 remaining, which we can divide and conquer
+    int n = 2;
+    if ((value & (~0L << 35)) != 0L) {
+      n += 4; value >>>= 28;
+    }
+    if ((value & (~0L << 21)) != 0L) {
+      n += 2; value >>>= 14;
+    }
+    if ((value & (~0L << 14)) != 0L) {
+      n += 1;
+    }
+    return n;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field.
+   */
+  public static int computeSInt64SizeNoTag(final long value) {
+    return computeUInt64SizeNoTag(encodeZigZag64(value));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field.
+   */
+  public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+    return FIXED64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field.
+   */
+  public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+    return FIXED64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
+    return FIXED32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
+    return FIXED64_SIZE;
   }
 
   /**
    * Compute the number of bytes that would be needed to encode a
    * {@code bool} field.
    */
-  public static int computeBoolSizeNoTag(final boolean value) {
+  public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) {
     return 1;
   }
 
   /**
+   * Compute the number of bytes that would be needed to encode an enum field.
+   * The provided value is the numeric value used to represent the enum value on the wire
+   * (not the enum ordinal value).
+   */
+  public static int computeEnumSizeNoTag(final int value) {
+    return computeInt32SizeNoTag(value);
+  }
+
+  /**
    * Compute the number of bytes that would be needed to encode a
    * {@code string} field.
    */
@@ -876,24 +873,7 @@
       length = bytes.length;
     }
 
-    return computeRawVarint32Size(length) + length;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field.
-   */
-  public static int computeGroupSizeNoTag(final MessageLite value) {
-    return value.getSerializedSize();
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an embedded
-   * message field.
-   */
-  public static int computeMessageSizeNoTag(final MessageLite value) {
-    final int size = value.getSerializedSize();
-    return computeRawVarint32Size(size) + size;
+    return computeLengthDelimitedFieldSize(length);
   }
 
   /**
@@ -901,8 +881,7 @@
    * message stored in lazy field.
    */
   public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
-    final int size = value.getSerializedSize();
-    return computeRawVarint32Size(size) + size;
+    return computeLengthDelimitedFieldSize(value.getSerializedSize());
   }
 
   /**
@@ -910,8 +889,7 @@
    * {@code bytes} field.
    */
   public static int computeBytesSizeNoTag(final ByteString value) {
-    return computeRawVarint32Size(value.size()) +
-           value.size();
+    return computeLengthDelimitedFieldSize(value.size());
   }
 
   /**
@@ -919,7 +897,7 @@
    * {@code bytes} field.
    */
   public static int computeByteArraySizeNoTag(final byte[] value) {
-    return computeRawVarint32Size(value.length) + value.length;
+    return computeLengthDelimitedFieldSize(value.length);
   }
 
   /**
@@ -927,380 +905,23 @@
    * {@code bytes} field.
    */
   public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
-    return computeRawVarint32Size(value.capacity()) + value.capacity();
+    return computeLengthDelimitedFieldSize(value.capacity());
   }
 
   /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint32} field.
+   * Compute the number of bytes that would be needed to encode an embedded
+   * message field.
    */
-  public static int computeUInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(value);
+  public static int computeMessageSizeNoTag(final MessageLite value) {
+    return computeLengthDelimitedFieldSize(value.getSerializedSize());
   }
 
-  /**
-   * Compute the number of bytes that would be needed to encode an enum field.
-   * Caller is responsible for converting the enum value to its numeric value.
-   */
-  public static int computeEnumSizeNoTag(final int value) {
-    return computeInt32SizeNoTag(value);
+
+  static int computeLengthDelimitedFieldSize(int fieldLength) {
+    return computeUInt32SizeNoTag(fieldLength) + fieldLength;
   }
 
   /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed32} field.
-   */
-  public static int computeSFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field.
-   */
-  public static int computeSFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field.
-   */
-  public static int computeSInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(encodeZigZag32(value));
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint64} field.
-   */
-  public static int computeSInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(encodeZigZag64(value));
-  }
-
-  // =================================================================
-
-  /**
-   * Internal helper that writes the current buffer to the output. The
-   * buffer position is reset to its initial value when this returns.
-   */
-  private void refreshBuffer() throws IOException {
-    if (output == null) {
-      // We're writing to a single buffer.
-      throw new OutOfSpaceException();
-    }
-
-    // Since we have an output stream, this is our buffer
-    // and buffer offset == 0
-    output.write(buffer, 0, position);
-    position = 0;
-  }
-
-  /**
-   * Flushes the stream and forces any buffered bytes to be written.  This
-   * does not flush the underlying OutputStream.
-   */
-  public void flush() throws IOException {
-    if (output != null) {
-      refreshBuffer();
-    }
-  }
-
-  /**
-   * If writing to a flat array, return the space left in the array.
-   * Otherwise, throws {@code UnsupportedOperationException}.
-   */
-  public int spaceLeft() {
-    if (output == null) {
-      return limit - position;
-    } else {
-      throw new UnsupportedOperationException(
-        "spaceLeft() can only be called on CodedOutputStreams that are " +
-        "writing to a flat array.");
-    }
-  }
-
-  /**
-   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
-   * a byte array that is exactly big enough to hold a message, then write to
-   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
-   * after writing verifies that the message was actually as big as expected,
-   * which can help catch bugs.
-   */
-  public void checkNoSpaceLeft() {
-    if (spaceLeft() != 0) {
-      throw new IllegalStateException(
-        "Did not write as much data as expected.");
-    }
-  }
-
-  /**
-   * If you create a CodedOutputStream around a simple flat array, you must
-   * not attempt to write more bytes than the array has space.  Otherwise,
-   * this exception will be thrown.
-   */
-  public static class OutOfSpaceException extends IOException {
-    private static final long serialVersionUID = -6947486886997889499L;
-
-    private static final String MESSAGE =
-        "CodedOutputStream was writing to a flat byte array and ran out of space.";
-
-    OutOfSpaceException() {
-      super(MESSAGE);
-    }
-
-    OutOfSpaceException(Throwable cause) {
-      super(MESSAGE, cause);
-    }
-  }
-
-  /**
-   * Get the total number of bytes successfully written to this stream.  The
-   * returned value is not guaranteed to be accurate if exceptions have been
-   * found in the middle of writing.
-   */
-  public int getTotalBytesWritten() {
-    return totalBytesWritten;
-  }
-
-  /** Write a single byte. */
-  public void writeRawByte(final byte value) throws IOException {
-    if (position == limit) {
-      refreshBuffer();
-    }
-
-    buffer[position++] = value;
-    ++totalBytesWritten;
-  }
-
-  /** Write a single byte, represented by an integer value. */
-  public void writeRawByte(final int value) throws IOException {
-    writeRawByte((byte) value);
-  }
-
-  /** Write a byte string. */
-  public void writeRawBytes(final ByteString value) throws IOException {
-    writeRawBytes(value, 0, value.size());
-  }
-
-  /** Write an array of bytes. */
-  public void writeRawBytes(final byte[] value) throws IOException {
-    writeRawBytes(value, 0, value.length);
-  }
-
-  /**
-   * Write a ByteBuffer. This method will write all content of the ByteBuffer
-   * regardless of the current position and limit (i.e., the number of bytes
-   * to be written is value.capacity(), not value.remaining()). Furthermore,
-   * this method doesn't alter the state of the passed-in ByteBuffer. Its
-   * position, limit, mark, etc. will remain unchanged. If you only want to
-   * write the remaining bytes of a ByteBuffer, you can call
-   * {@code writeRawBytes(byteBuffer.slice())}.
-   */
-  public void writeRawBytes(final ByteBuffer value) throws IOException {
-    if (value.hasArray()) {
-      writeRawBytes(value.array(), value.arrayOffset(), value.capacity());
-    } else {
-      ByteBuffer duplicated = value.duplicate();
-      duplicated.clear();
-      writeRawBytesInternal(duplicated);
-    }
-  }
-
-  /** Write a ByteBuffer that isn't backed by an array. */
-  private void writeRawBytesInternal(final ByteBuffer value)
-      throws IOException {
-    int length = value.remaining();
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      value.get(buffer, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      value.get(buffer, position, bytesWritten);
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      while (length > limit) {
-        // Copy data into the buffer before writing it to OutputStream.
-        // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy.
-        value.get(buffer, 0, limit);
-        output.write(buffer, 0, limit);
-        length -= limit;
-        totalBytesWritten += limit;
-      }
-      value.get(buffer, 0, length);
-      position = length;
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Write part of an array of bytes. */
-  public void writeRawBytes(final byte[] value, int offset, int length)
-                            throws IOException {
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      System.arraycopy(value, offset, buffer, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      System.arraycopy(value, offset, buffer, position, bytesWritten);
-      offset += bytesWritten;
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      if (length <= limit) {
-        // Fits in new buffer.
-        System.arraycopy(value, offset, buffer, 0, length);
-        position = length;
-      } else {
-        // Write is very big.  Let's do it all at once.
-        output.write(value, offset, length);
-      }
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Write part of a byte string. */
-  public void writeRawBytes(final ByteString value, int offset, int length)
-                            throws IOException {
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      value.copyTo(buffer, offset, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      value.copyTo(buffer, offset, position, bytesWritten);
-      offset += bytesWritten;
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      if (length <= limit) {
-        // Fits in new buffer.
-        value.copyTo(buffer, offset, 0, length);
-        position = length;
-      } else {
-        value.writeTo(output, offset, length);
-      }
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Encode and write a tag. */
-  public void writeTag(final int fieldNumber, final int wireType)
-                       throws IOException {
-    writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
-  }
-
-  /** Compute the number of bytes that would be needed to encode a tag. */
-  public static int computeTagSize(final int fieldNumber) {
-    return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
-  }
-
-  /**
-   * Encode and write a varint.  {@code value} is treated as
-   * unsigned, so it won't be sign-extended if negative.
-   */
-  public void writeRawVarint32(int value) throws IOException {
-    while (true) {
-      if ((value & ~0x7F) == 0) {
-        writeRawByte(value);
-        return;
-      } else {
-        writeRawByte((value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a varint.
-   * {@code value} is treated as unsigned, so it won't be sign-extended if
-   * negative.
-   */
-  public static int computeRawVarint32Size(final int value) {
-    if ((value & (~0 <<  7)) == 0) return 1;
-    if ((value & (~0 << 14)) == 0) return 2;
-    if ((value & (~0 << 21)) == 0) return 3;
-    if ((value & (~0 << 28)) == 0) return 4;
-    return 5;
-  }
-
-  /** Encode and write a varint. */
-  public void writeRawVarint64(long value) throws IOException {
-    while (true) {
-      if ((value & ~0x7FL) == 0) {
-        writeRawByte((int)value);
-        return;
-      } else {
-        writeRawByte(((int)value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /** Compute the number of bytes that would be needed to encode a varint. */
-  public static int computeRawVarint64Size(long value) {
-    // handle two popular special cases up front ...
-    if ((value & (~0L << 7)) == 0L) return 1;
-    if (value < 0L) return 10;
-    // ... leaving us with 8 remaining, which we can divide and conquer
-    int n = 2;
-    if ((value & (~0L << 35)) != 0L) { n += 4; value >>>= 28; }
-    if ((value & (~0L << 21)) != 0L) { n += 2; value >>>= 14; }
-    if ((value & (~0L << 14)) != 0L) { n += 1; }
-    return n;
-  }
-
-  /** Write a little-endian 32-bit integer. */
-  public void writeRawLittleEndian32(final int value) throws IOException {
-    writeRawByte((value      ) & 0xFF);
-    writeRawByte((value >>  8) & 0xFF);
-    writeRawByte((value >> 16) & 0xFF);
-    writeRawByte((value >> 24) & 0xFF);
-  }
-
-  public static final int LITTLE_ENDIAN_32_SIZE = 4;
-
-  /** Write a little-endian 64-bit integer. */
-  public void writeRawLittleEndian64(final long value) throws IOException {
-    writeRawByte((int)(value      ) & 0xFF);
-    writeRawByte((int)(value >>  8) & 0xFF);
-    writeRawByte((int)(value >> 16) & 0xFF);
-    writeRawByte((int)(value >> 24) & 0xFF);
-    writeRawByte((int)(value >> 32) & 0xFF);
-    writeRawByte((int)(value >> 40) & 0xFF);
-    writeRawByte((int)(value >> 48) & 0xFF);
-    writeRawByte((int)(value >> 56) & 0xFF);
-  }
-
-  public static final int LITTLE_ENDIAN_64_SIZE = 8;
-
-  /**
    * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
    * into values that can be efficiently encoded with varint.  (Otherwise,
    * negative values must be sign-extended to 64 bits to be varint encoded,
@@ -1329,4 +950,2058 @@
     // Note:  the right-shift must be arithmetic
     return (n << 1) ^ (n >> 63);
   }
+
+  // =================================================================
+
+  /**
+   * Flushes the stream and forces any buffered bytes to be written.  This
+   * does not flush the underlying OutputStream.
+   */
+  public abstract void flush() throws IOException;
+
+  /**
+   * If writing to a flat array, return the space left in the array.
+   * Otherwise, throws {@code UnsupportedOperationException}.
+   */
+  public abstract int spaceLeft();
+
+  /**
+   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
+   * a byte array that is exactly big enough to hold a message, then write to
+   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
+   * after writing verifies that the message was actually as big as expected,
+   * which can help catch bugs.
+   */
+  public final void checkNoSpaceLeft() {
+    if (spaceLeft() != 0) {
+      throw new IllegalStateException("Did not write as much data as expected.");
+    }
+  }
+
+  /**
+   * If you create a CodedOutputStream around a simple flat array, you must
+   * not attempt to write more bytes than the array has space.  Otherwise,
+   * this exception will be thrown.
+   */
+  public static class OutOfSpaceException extends IOException {
+    private static final long serialVersionUID = -6947486886997889499L;
+
+    private static final String MESSAGE =
+        "CodedOutputStream was writing to a flat byte array and ran out of space.";
+
+    OutOfSpaceException() {
+      super(MESSAGE);
+    }
+
+    OutOfSpaceException(String explanationMessage) {
+      super(MESSAGE + ": " + explanationMessage);
+    }
+
+    OutOfSpaceException(Throwable cause) {
+      super(MESSAGE, cause);
+    }
+
+    OutOfSpaceException(String explanationMessage, Throwable cause) {
+      super(MESSAGE + ": " + explanationMessage, cause);
+    }
+  }
+
+  /**
+   * Get the total number of bytes successfully written to this stream.  The
+   * returned value is not guaranteed to be accurate if exceptions have been
+   * found in the middle of writing.
+   */
+  public abstract int getTotalBytesWritten();
+
+  // =================================================================
+
+  /** Write a {@code bytes} field to the stream. Visible for testing. */
+  abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length)
+      throws IOException;
+
+  final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause)
+      throws IOException {
+    logger.log(Level.WARNING,
+        "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause);
+
+    // Unfortunately there does not appear to be any way to tell Java to encode
+    // UTF-8 directly into our buffer, so we have to let it create its own byte
+    // array and then copy.
+    // TODO(dweis): Consider using nio Charset methods instead.
+    final byte[] bytes = value.getBytes(Internal.UTF_8);
+    try {
+      writeUInt32NoTag(bytes.length);
+      writeLazy(bytes, 0, bytes.length);
+    } catch (IndexOutOfBoundsException e) {
+      throw new OutOfSpaceException(e);
+    } catch (OutOfSpaceException e) {
+      throw e;
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Write a {@code group} field, including tag, to the stream.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException {
+    writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+    writeGroupNoTag(value);
+    writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+  }
+
+
+  /**
+   * Write a {@code group} field to the stream.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public final void writeGroupNoTag(final MessageLite value) throws IOException {
+    value.writeTo(this);
+  }
+
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field, including tag.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public static int computeGroupSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+  }
+
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field.
+   */
+  @Deprecated
+  public static int computeGroupSizeNoTag(final MessageLite value) {
+    return value.getSerializedSize();
+  }
+
+
+  /**
+   * Encode and write a varint.  {@code value} is treated as
+   * unsigned, so it won't be sign-extended if negative.
+   *
+   * @deprecated use {@link #writeUInt32NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawVarint32(int value) throws IOException {
+    writeUInt32NoTag(value);
+  }
+
+  /**
+   * Encode and write a varint.
+   *
+   * @deprecated use {@link #writeUInt64NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawVarint64(long value) throws IOException {
+    writeUInt64NoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   * {@code value} is treated as unsigned, so it won't be sign-extended if
+   * negative.
+   *
+   * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
+   */
+  @Deprecated
+  public static int computeRawVarint32Size(final int value) {
+    return computeUInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   *
+   * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead.
+   */
+  @Deprecated
+  public static int computeRawVarint64Size(long value) {
+    return computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Write a little-endian 32-bit integer.
+   *
+   * @deprecated Use {@link #writeFixed32NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawLittleEndian32(final int value) throws IOException {
+    writeFixed32NoTag(value);
+  }
+
+  /**
+   * Write a little-endian 64-bit integer.
+   *
+   * @deprecated Use {@link #writeFixed64NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawLittleEndian64(final long value) throws IOException {
+    writeFixed64NoTag(value);
+  }
+
+  // =================================================================
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a byte array.
+   */
+  private static class ArrayEncoder extends CodedOutputStream {
+    private final byte[] buffer;
+    private final int offset;
+    private final int limit;
+    private int position;
+
+    ArrayEncoder(byte[] buffer, int offset, int length) {
+      if (buffer == null) {
+        throw new NullPointerException("buffer");
+      }
+      if ((offset | length | (buffer.length - (offset + length))) < 0) {
+        throw new IllegalArgumentException(String.format(
+            "Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
+            buffer.length, offset, length));
+      }
+      this.buffer = buffer;
+      this.offset = offset;
+      position = offset;
+      limit = offset + length;
+    }
+
+    @Override
+    public final void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public final void writeInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeInt32NoTag(value);
+    }
+
+    @Override
+    public final void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt32NoTag(value);
+    }
+
+    @Override
+    public final void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      writeFixed32NoTag(value);
+    }
+
+    @Override
+    public final void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt64NoTag(value);
+    }
+
+    @Override
+    public final void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      writeFixed64NoTag(value);
+    }
+
+    @Override
+    public final void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      write((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public final void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public final void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public final void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public final void writeByteArrayNoTag(final byte[] value, int offset, int length)
+        throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public final void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public final void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+
+    @Override
+    public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public final void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+
+    @Override
+    public final void write(byte value) throws IOException {
+      try {
+        buffer[position++] = value;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
+      }
+    }
+
+    @Override
+    public final void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public final void writeUInt32NoTag(int value) throws IOException {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            UnsafeUtil.putByte(buffer, position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } else {
+        try {
+          while (true) {
+            if ((value & ~0x7F) == 0) {
+              buffer[position++] = (byte) value;
+              return;
+            } else {
+              buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+              value >>>= 7;
+            }
+          }
+        } catch (IndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(
+              String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
+        }
+      }
+    }
+
+    @Override
+    public final void writeFixed32NoTag(int value) throws IOException {
+      try {
+        buffer[position++] = (byte) (value & 0xFF);
+        buffer[position++] = (byte) ((value >> 8) & 0xFF);
+        buffer[position++] = (byte) ((value >> 16) & 0xFF);
+        buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
+      }
+    }
+
+    @Override
+    public final void writeUInt64NoTag(long value) throws IOException {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            UnsafeUtil.putByte(buffer, position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } else {
+        try {
+          while (true) {
+            if ((value & ~0x7FL) == 0) {
+              buffer[position++] = (byte) value;
+              return;
+            } else {
+              buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+              value >>>= 7;
+            }
+          }
+        } catch (IndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(
+              String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
+        }
+      }
+    }
+
+    @Override
+    public final void writeFixed64NoTag(long value) throws IOException {
+      try {
+        buffer[position++] = (byte) ((int) (value) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 8) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 16) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 24) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
+      }
+    }
+
+    @Override
+    public final void write(byte[] value, int offset, int length) throws IOException {
+      try {
+        System.arraycopy(value, offset, buffer, position, length);
+        position += length;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
+      }
+    }
+
+    @Override
+    public final void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public final void write(ByteBuffer value) throws IOException {
+      final int length = value.remaining();
+      try {
+        value.get(buffer, position, length);
+        position += length;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
+      }
+    }
+
+    @Override
+    public final void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    @Override
+    public final void writeStringNoTag(String value) throws IOException {
+      final int oldPosition = position;
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          position = oldPosition + minLengthVarIntSize;
+          int newPosition = Utf8.encode(value, buffer, position, spaceLeft());
+          // Since this class is stateful and tracks the position, we rewind and store the state,
+          // prepend the length, then reset it back to the end of the string.
+          position = oldPosition;
+          int length = newPosition - oldPosition - minLengthVarIntSize;
+          writeUInt32NoTag(length);
+          position = newPosition;
+        } else {
+          int length = Utf8.encodedLength(value);
+          writeUInt32NoTag(length);
+          position = Utf8.encode(value, buffer, position, spaceLeft());
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change - we fall back to inefficient path.
+        position = oldPosition;
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() {
+      // Do nothing.
+    }
+
+    @Override
+    public final int spaceLeft() {
+      return limit - position;
+    }
+
+    @Override
+    public final int getTotalBytesWritten() {
+      return position - offset;
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
+   * done directly to the underlying array. The buffer position is only updated after a flush.
+   */
+  private static final class HeapNioEncoder extends ArrayEncoder {
+    private final ByteBuffer byteBuffer;
+    private int initialPosition;
+
+    HeapNioEncoder(ByteBuffer byteBuffer) {
+      super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
+          byteBuffer.remaining());
+      this.byteBuffer = byteBuffer;
+      this.initialPosition = byteBuffer.position();
+    }
+
+    @Override
+    public void flush() {
+      // Update the position on the buffer.
+      byteBuffer.position(initialPosition + getTotalBytesWritten());
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer}, using only
+   * safe operations..
+   */
+  private static final class SafeDirectNioEncoder extends CodedOutputStream {
+    private final ByteBuffer originalBuffer;
+    private final ByteBuffer buffer;
+    private final int initialPosition;
+
+    SafeDirectNioEncoder(ByteBuffer buffer) {
+      this.originalBuffer = buffer;
+      this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+      initialPosition = buffer.position();
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      writeFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      writeFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      write((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+
+    @Override
+    public void write(byte value) throws IOException {
+      try {
+        buffer.put(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      try {
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            buffer.put((byte) value);
+            return;
+          } else {
+            buffer.put((byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeFixed32NoTag(int value) throws IOException {
+      try {
+        buffer.putInt(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      try {
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            buffer.put((byte) value);
+            return;
+          } else {
+            buffer.put((byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeFixed64NoTag(long value) throws IOException {
+      try {
+        buffer.putLong(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length) throws IOException {
+      try {
+        buffer.put(value, offset, length);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      try {
+        buffer.put(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      final int startPos = buffer.position();
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          // Save the current position and increment past the length field. We'll come back
+          // and write the length field after the encoding is complete.
+          final int startOfBytes = buffer.position() + minLengthVarIntSize;
+          buffer.position(startOfBytes);
+
+          // Encode the string.
+          encode(value);
+
+          // Now go back to the beginning and write the length.
+          int endOfBytes = buffer.position();
+          buffer.position(startPos);
+          writeUInt32NoTag(endOfBytes - startOfBytes);
+
+          // Reposition the buffer past the written data.
+          buffer.position(endOfBytes);
+        } else {
+          final int length = Utf8.encodedLength(value);
+          writeUInt32NoTag(length);
+          encode(value);
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change and convert to an IOException.
+        buffer.position(startPos);
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IllegalArgumentException e) {
+        // Thrown by buffer.position() if out of range.
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() {
+      // Update the position of the original buffer.
+      originalBuffer.position(buffer.position());
+    }
+
+    @Override
+    public int spaceLeft() {
+      return buffer.remaining();
+    }
+
+    @Override
+    public int getTotalBytesWritten() {
+      return buffer.position() - initialPosition;
+    }
+
+    private void encode(String value) throws IOException {
+      try {
+        Utf8.encodeUtf8(value, buffer);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer} using {@code
+   * sun.misc.Unsafe}.
+   */
+  private static final class UnsafeDirectNioEncoder extends CodedOutputStream {
+    private final ByteBuffer originalBuffer;
+    private final ByteBuffer buffer;
+    private final long address;
+    private final long initialPosition;
+    private final long limit;
+    private final long oneVarintLimit;
+    private long position;
+
+    UnsafeDirectNioEncoder(ByteBuffer buffer) {
+      this.originalBuffer = buffer;
+      this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+      address = UnsafeUtil.addressOffset(buffer);
+      initialPosition = address + buffer.position();
+      limit = address + buffer.limit();
+      oneVarintLimit = limit - MAX_VARINT_SIZE;
+      position = initialPosition;
+    }
+
+    static boolean isSupported() {
+      return UnsafeUtil.hasUnsafeByteBufferOperations();
+    }
+
+    @Override
+    public void writeTag(int fieldNumber, int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(int fieldNumber, int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(int fieldNumber, int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(int fieldNumber, int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      writeFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(int fieldNumber, long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(int fieldNumber, long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      writeFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(int fieldNumber, boolean value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      write((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(int fieldNumber, String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(int fieldNumber, ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(int fieldNumber, byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeMessage(int fieldNumber, MessageLite value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+
+    @Override
+    public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(int fieldNumber, ByteString value) throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+
+    @Override
+    public void write(byte value) throws IOException {
+      if (position >= limit) {
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
+      }
+      UnsafeUtil.putByte(position++, value);
+    }
+
+    @Override
+    public void writeBytesNoTag(ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      if (position <= oneVarintLimit) {
+        // Optimization to avoid bounds checks on each iteration.
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            UnsafeUtil.putByte(position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } else {
+        while (position < limit) {
+          if ((value & ~0x7F) == 0) {
+            UnsafeUtil.putByte(position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
+      }
+    }
+
+    @Override
+    public void writeFixed32NoTag(int value) throws IOException {
+      buffer.putInt(bufferPos(position), value);
+      position += FIXED32_SIZE;
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      if (position <= oneVarintLimit) {
+        // Optimization to avoid bounds checks on each iteration.
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            UnsafeUtil.putByte(position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } else {
+        while (position < limit) {
+          if ((value & ~0x7FL) == 0) {
+            UnsafeUtil.putByte(position++, (byte) value);
+            return;
+          } else {
+            UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
+      }
+    }
+
+    @Override
+    public void writeFixed64NoTag(long value) throws IOException {
+      buffer.putLong(bufferPos(position), value);
+      position += FIXED64_SIZE;
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length) throws IOException {
+      if (value == null
+          || offset < 0
+          || length < 0
+          || (value.length - length) < offset
+          || (limit - length) < position) {
+        if (value == null) {
+          throw new NullPointerException("value");
+        }
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, length));
+      }
+
+      UnsafeUtil.copyMemory(value, offset, position, length);
+      position += length;
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      try {
+        int length = value.remaining();
+        repositionBuffer(position);
+        buffer.put(value);
+        position += length;
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      long prevPos = position;
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
+        int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          // Save the current position and increment past the length field. We'll come back
+          // and write the length field after the encoding is complete.
+          int stringStart = bufferPos(position) + minLengthVarIntSize;
+          buffer.position(stringStart);
+
+          // Encode the string.
+          Utf8.encodeUtf8(value, buffer);
+
+          // Write the length and advance the position.
+          int length = buffer.position() - stringStart;
+          writeUInt32NoTag(length);
+          position += length;
+        } else {
+          // Calculate and write the encoded length.
+          int length = Utf8.encodedLength(value);
+          writeUInt32NoTag(length);
+
+          // Write the string and advance the position.
+          repositionBuffer(position);
+          Utf8.encodeUtf8(value, buffer);
+          position += length;
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change and convert to an IOException.
+        position = prevPos;
+        repositionBuffer(position);
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IllegalArgumentException e) {
+        // Thrown by buffer.position() if out of range.
+        throw new OutOfSpaceException(e);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() {
+      // Update the position of the original buffer.
+      originalBuffer.position(bufferPos(position));
+    }
+
+    @Override
+    public int spaceLeft() {
+      return (int) (limit - position);
+    }
+
+    @Override
+    public int getTotalBytesWritten() {
+      return (int) (position - initialPosition);
+    }
+
+    private void repositionBuffer(long pos) {
+      buffer.position(bufferPos(pos));
+    }
+
+    private int bufferPos(long pos) {
+      return (int) (pos - address);
+    }
+  }
+
+  /**
+   * Abstract base class for buffered encoders.
+   */
+  private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
+    final byte[] buffer;
+    final int limit;
+    int position;
+    int totalBytesWritten;
+
+    AbstractBufferedEncoder(int bufferSize) {
+      if (bufferSize < 0) {
+        throw new IllegalArgumentException("bufferSize must be >= 0");
+      }
+      // As an optimization, we require that the buffer be able to store at least 2
+      // varints so that we can buffer any integer write (tag + value). This reduces the
+      // number of range checks for a single write to 1 (i.e. if there is not enough space
+      // to buffer the tag+value, flush and then buffer it).
+      this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)];
+      this.limit = buffer.length;
+    }
+
+    @Override
+    public final int spaceLeft() {
+      throw new UnsupportedOperationException(
+          "spaceLeft() can only be called on CodedOutputStreams that are "
+              + "writing to a flat array or ByteBuffer.");
+    }
+
+    @Override
+    public final int getTotalBytesWritten() {
+      return totalBytesWritten;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void buffer(byte value) {
+      buffer[position++] = value;
+      totalBytesWritten++;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferTag(final int fieldNumber, final int wireType) {
+      bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferInt32NoTag(final int value) {
+      if (value >= 0) {
+        bufferUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        bufferUInt64NoTag(value);
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferUInt32NoTag(int value) {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+        final long originalPos = position;
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            UnsafeUtil.putByte(buffer, position++, (byte) value);
+            break;
+          } else {
+            UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        int delta = (int) (position - originalPos);
+        totalBytesWritten += delta;
+      } else {
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            buffer[position++] = (byte) value;
+            totalBytesWritten++;
+            return;
+          } else {
+            buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+            totalBytesWritten++;
+            value >>>= 7;
+          }
+        }
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferUInt64NoTag(long value) {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+        final long originalPos = position;
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            UnsafeUtil.putByte(buffer, position++, (byte) value);
+            break;
+          } else {
+            UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        int delta = (int) (position - originalPos);
+        totalBytesWritten += delta;
+      } else {
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            buffer[position++] = (byte) value;
+            totalBytesWritten++;
+            return;
+          } else {
+            buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+            totalBytesWritten++;
+            value >>>= 7;
+          }
+        }
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferFixed32NoTag(int value) {
+      buffer[position++] = (byte) (value & 0xFF);
+      buffer[position++] = (byte) ((value >> 8) & 0xFF);
+      buffer[position++] = (byte) ((value >> 16) & 0xFF);
+      buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      totalBytesWritten += FIXED32_SIZE;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferFixed64NoTag(long value) {
+      buffer[position++] = (byte) (value & 0xFF);
+      buffer[position++] = (byte) ((value >> 8) & 0xFF);
+      buffer[position++] = (byte) ((value >> 16) & 0xFF);
+      buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+      totalBytesWritten += FIXED64_SIZE;
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to
+   * support string encoding operations. All other writes are just passed through to the
+   * {@link ByteOutput}.
+   */
+  private static final class ByteOutputEncoder extends AbstractBufferedEncoder {
+    private final ByteOutput out;
+
+    ByteOutputEncoder(ByteOutput out, int bufferSize) {
+      super(bufferSize);
+      if (out == null) {
+        throw new NullPointerException("out");
+      }
+      this.out = out;
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      buffer((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+
+    @Override
+    public void write(byte value) throws IOException {
+      if (position == limit) {
+        doFlush();
+      }
+
+      buffer(value);
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32NoTag(final int value) throws IOException {
+      flushIfNotAvailable(FIXED32_SIZE);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64NoTag(final long value) throws IOException {
+      flushIfNotAvailable(FIXED64_SIZE);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+      // and at most 3 times of it. We take advantage of this in both branches below.
+      final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+      final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+      // If we are streaming and the potential length is too big to fit in our buffer, we take the
+      // slower path.
+      if (maxLengthVarIntSize + maxLength > limit) {
+        // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+        // does the same internally and then does *another copy* to return a byte[] of exactly the
+        // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+        // UTF-8 encoded bytes.
+        final byte[] encodedBytes = new byte[maxLength];
+        int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+        writeUInt32NoTag(actualLength);
+        writeLazy(encodedBytes, 0, actualLength);
+        return;
+      }
+
+      // Fast path: we have enough space available in our buffer for the string...
+      if (maxLengthVarIntSize + maxLength > limit - position) {
+        // Flush to free up space.
+        doFlush();
+      }
+
+      final int oldPosition = position;
+      try {
+        // Optimize for the case where we know this length results in a constant varint length as
+        // this saves a pass for measuring the length of the string.
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          position = oldPosition + minLengthVarIntSize;
+          int newPosition = Utf8.encode(value, buffer, position, limit - position);
+          // Since this class is stateful and tracks the position, we rewind and store the state,
+          // prepend the length, then reset it back to the end of the string.
+          position = oldPosition;
+          int length = newPosition - oldPosition - minLengthVarIntSize;
+          bufferUInt32NoTag(length);
+          position = newPosition;
+          totalBytesWritten += length;
+        } else {
+          int length = Utf8.encodedLength(value);
+          bufferUInt32NoTag(length);
+          position = Utf8.encode(value, buffer, position, length);
+          totalBytesWritten += length;
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change and convert to an IOException.
+        totalBytesWritten -= position - oldPosition;
+        position = oldPosition;
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() throws IOException {
+      if (position > 0) {
+        // Flush the buffer.
+        doFlush();
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length) throws IOException {
+      flush();
+      out.write(value, offset, length);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      flush();
+      out.writeLazy(value, offset, length);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      flush();
+      int length = value.remaining();
+      out.write(value);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      flush();
+      int length = value.remaining();
+      out.writeLazy(value);
+      totalBytesWritten += length;
+    }
+
+    private void flushIfNotAvailable(int requiredSize) throws IOException {
+      if (limit - position < requiredSize) {
+        doFlush();
+      }
+    }
+
+    private void doFlush() throws IOException {
+      out.write(buffer, 0, position);
+      position = 0;
+    }
+  }
+
+  /**
+   * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal
+   * buffering to optimize writes to the {@link OutputStream}.
+   */
+  private static final class OutputStreamEncoder extends AbstractBufferedEncoder {
+    private final OutputStream out;
+
+    OutputStreamEncoder(OutputStream out, int bufferSize) {
+      super(bufferSize);
+      if (out == null) {
+        throw new NullPointerException("out");
+      }
+      this.out = out;
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      buffer((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+
+    @Override
+    public void write(byte value) throws IOException {
+      if (position == limit) {
+        doFlush();
+      }
+
+      buffer(value);
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32NoTag(final int value) throws IOException {
+      flushIfNotAvailable(FIXED32_SIZE);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64NoTag(final long value) throws IOException {
+      flushIfNotAvailable(FIXED64_SIZE);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+        // If we are streaming and the potential length is too big to fit in our buffer, we take the
+        // slower path.
+        if (maxLengthVarIntSize + maxLength > limit) {
+          // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+          // does the same internally and then does *another copy* to return a byte[] of exactly the
+          // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+          // UTF-8 encoded bytes.
+          final byte[] encodedBytes = new byte[maxLength];
+          int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+          writeUInt32NoTag(actualLength);
+          writeLazy(encodedBytes, 0, actualLength);
+          return;
+        }
+
+        // Fast path: we have enough space available in our buffer for the string...
+        if (maxLengthVarIntSize + maxLength > limit - position) {
+          // Flush to free up space.
+          doFlush();
+        }
+
+        // Optimize for the case where we know this length results in a constant varint length as
+        // this saves a pass for measuring the length of the string.
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        int oldPosition = position;
+        final int length;
+        try {
+          if (minLengthVarIntSize == maxLengthVarIntSize) {
+            position = oldPosition + minLengthVarIntSize;
+            int newPosition = Utf8.encode(value, buffer, position, limit - position);
+            // Since this class is stateful and tracks the position, we rewind and store the
+            // state, prepend the length, then reset it back to the end of the string.
+            position = oldPosition;
+            length = newPosition - oldPosition - minLengthVarIntSize;
+            bufferUInt32NoTag(length);
+            position = newPosition;
+          } else {
+            length = Utf8.encodedLength(value);
+            bufferUInt32NoTag(length);
+            position = Utf8.encode(value, buffer, position, length);
+          }
+          totalBytesWritten += length;
+        } catch (UnpairedSurrogateException e) {
+          // Be extra careful and restore the original position for retrying the write with the
+          // less efficient path.
+          totalBytesWritten -= position - oldPosition;
+          position = oldPosition;
+          throw e;
+        } catch (ArrayIndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(e);
+        }
+      } catch (UnpairedSurrogateException e) {
+        inefficientWriteStringNoTag(value, e);
+      }
+    }
+
+    @Override
+    public void flush() throws IOException {
+      if (position > 0) {
+        // Flush the buffer.
+        doFlush();
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length)
+        throws IOException {
+      if (limit - position >= length) {
+        // We have room in the current buffer.
+        System.arraycopy(value, offset, buffer, position, length);
+        position += length;
+        totalBytesWritten += length;
+      } else {
+        // Write extends past current buffer.  Fill the rest of this buffer and
+        // flush.
+        final int bytesWritten = limit - position;
+        System.arraycopy(value, offset, buffer, position, bytesWritten);
+        offset += bytesWritten;
+        length -= bytesWritten;
+        position = limit;
+        totalBytesWritten += bytesWritten;
+        doFlush();
+
+        // Now deal with the rest.
+        // Since we have an output stream, this is our buffer
+        // and buffer offset == 0
+        if (length <= limit) {
+          // Fits in new buffer.
+          System.arraycopy(value, offset, buffer, 0, length);
+          position = length;
+        } else {
+          // Write is very big.  Let's do it all at once.
+          out.write(value, offset, length);
+        }
+        totalBytesWritten += length;
+      }
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      int length = value.remaining();
+      if (limit - position >= length) {
+        // We have room in the current buffer.
+        value.get(buffer, position, length);
+        position += length;
+        totalBytesWritten += length;
+      } else {
+        // Write extends past current buffer.  Fill the rest of this buffer and
+        // flush.
+        final int bytesWritten = limit - position;
+        value.get(buffer, position, bytesWritten);
+        length -= bytesWritten;
+        position = limit;
+        totalBytesWritten += bytesWritten;
+        doFlush();
+
+        // Now deal with the rest.
+        // Since we have an output stream, this is our buffer
+        // and buffer offset == 0
+        while (length > limit) {
+          // Copy data into the buffer before writing it to OutputStream.
+          value.get(buffer, 0, limit);
+          out.write(buffer, 0, limit);
+          length -= limit;
+          totalBytesWritten += limit;
+        }
+        value.get(buffer, 0, length);
+        position = length;
+        totalBytesWritten += length;
+      }
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    private void flushIfNotAvailable(int requiredSize) throws IOException {
+      if (limit - position < requiredSize) {
+        doFlush();
+      }
+    }
+
+    private void doFlush() throws IOException {
+      out.write(buffer, 0, position);
+      position = 0;
+    }
+  }
 }
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 5e15cfb..75b16fe 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -30,9 +30,10 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.Internal.checkNotNull;
+
 import com.google.protobuf.DescriptorProtos.*;
 import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
-
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -74,16 +75,28 @@
    */
   public static final class FileDescriptor extends GenericDescriptor {
     /** Convert the descriptor to its protocol message representation. */
-    public FileDescriptorProto toProto() { return proto; }
+    @Override
+    public FileDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the file name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /** Returns this object. */
-    public FileDescriptor getFile() { return this; }
+    @Override
+    public FileDescriptor getFile() {
+      return this;
+    }
 
     /** Returns the same as getName(). */
-    public String getFullName() { return proto.getName(); }
+    @Override
+    public String getFullName() {
+      return proto.getName();
+    }
 
     /**
      * Get the proto package name.  This is the package name given by the
@@ -272,7 +285,7 @@
      *           because a field has an undefined type or because two messages
      *           were defined with the same name.
      */
-    private static FileDescriptor buildFrom(
+    public static FileDescriptor buildFrom(
         final FileDescriptorProto proto, final FileDescriptor[] dependencies,
         final boolean allowUnknownDependencies)
         throws DescriptorValidationException {
@@ -582,10 +595,16 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public DescriptorProto toProto() { return proto; }
+    @Override
+    public DescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /**
      * Get the type's fully-qualified name, within the proto language's
@@ -598,10 +617,16 @@
      * </pre>
      * {@code Baz}'s full name is "foo.bar.Baz".
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** If this is a nested type, get the outer descriptor, otherwise null. */
     public Descriptor getContainingType() { return containingType; }
@@ -658,9 +683,7 @@
 
     /** Determines if the given field name is reserved. */
     public boolean isReservedName(final String name) {
-      if (name == null) {
-        throw new NullPointerException();
-      }
+      checkNotNull(name);
       for (final String reservedName : proto.getReservedNameList()) {
         if (reservedName.equals(name)) {
           return true;
@@ -847,6 +870,10 @@
         nestedTypes[i].setProto(proto.getNestedType(i));
       }
 
+      for (int i = 0; i < oneofs.length; i++) {
+        oneofs[i].setProto(proto.getOneofDecl(i));
+      }
+
       for (int i = 0; i < enumTypes.length; i++) {
         enumTypes[i].setProto(proto.getEnumType(i));
       }
@@ -875,19 +902,31 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public FieldDescriptorProto toProto() { return proto; }
+    @Override
+    public FieldDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the field's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /** Get the field's number. */
-    public int getNumber() { return proto.getNumber(); }
+    @Override
+    public int getNumber() {
+      return proto.getNumber();
+    }
 
     /**
      * Get the field's fully-qualified name.
      * @see Descriptors.Descriptor#getFullName()
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the JSON name of this field. */
     public String getJsonName() {
@@ -901,17 +940,22 @@
     public JavaType getJavaType() { return type.getJavaType(); }
 
     /** For internal use only. */
+    @Override
     public WireFormat.JavaType getLiteJavaType() {
       return getLiteType().getJavaType();
     }
 
     /** Get the {@code FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** Get the field's declared type. */
     public Type getType() { return type; }
 
     /** For internal use only. */
+    @Override
     public WireFormat.FieldType getLiteType() {
       return table[type.ordinal()];
     }
@@ -953,6 +997,7 @@
     }
 
     /** Is this field declared repeated? */
+    @Override
     public boolean isRepeated() {
       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
     }
@@ -960,6 +1005,7 @@
     /** Does this field have the {@code [packed = true]} option or is this field
      *  packable in proto3 and not explicitly setted to unpacked?
      */
+    @Override
     public boolean isPacked() {
       if (!isPackable()) {
         return false;
@@ -1048,6 +1094,7 @@
     }
 
     /** For enum fields, gets the field's type. */
+    @Override
     public EnumDescriptor getEnumType() {
       if (getJavaType() != JavaType.ENUM) {
         throw new UnsupportedOperationException(
@@ -1066,6 +1113,7 @@
      * @return negative, zero, or positive if {@code this} is less than,
      *         equal to, or greater than {@code other}, respectively.
      */
+    @Override
     public int compareTo(final FieldDescriptor other) {
       if (other.containingType != containingType) {
         throw new IllegalArgumentException(
@@ -1123,7 +1171,7 @@
       private JavaType javaType;
 
       public FieldDescriptorProto.Type toProto() {
-        return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
+        return FieldDescriptorProto.Type.forNumber(ordinal() + 1);
       }
       public JavaType getJavaType() { return javaType; }
 
@@ -1163,33 +1211,20 @@
       private final Object defaultDefault;
     }
 
-    // TODO(xiaofeng): Implement it consistently across different languages. See b/24751348.
-    private static String fieldNameToLowerCamelCase(String name) {
+    // This method should match exactly with the ToJsonName() function in C++
+    // descriptor.cc.
+    private static String fieldNameToJsonName(String name) {
       StringBuilder result = new StringBuilder(name.length());
       boolean isNextUpperCase = false;
       for (int i = 0; i < name.length(); i++) {
         Character ch = name.charAt(i);
-        if (Character.isLowerCase(ch)) {
-          if (isNextUpperCase) {
-            result.append(Character.toUpperCase(ch));
-          } else {
-            result.append(ch);
-          }
-          isNextUpperCase = false;
-        } else if (Character.isUpperCase(ch)) {
-          if (i == 0) {
-            // Force first letter to lower-case.
-            result.append(Character.toLowerCase(ch));
-          } else {
-            // Capital letters after the first are left as-is.
-            result.append(ch);
-          }
-          isNextUpperCase = false;
-        } else if (Character.isDigit(ch)) {
-          result.append(ch);
+        if (ch == '_') {
+          isNextUpperCase = true;
+        } else if (isNextUpperCase) {
+          result.append(Character.toUpperCase(ch));
           isNextUpperCase = false;
         } else {
-          isNextUpperCase = true;
+          result.append(ch);
         }
       }
       return result.toString();
@@ -1208,7 +1243,7 @@
       if (proto.hasJsonName()) {
         jsonName = proto.getJsonName();
       } else {
-        jsonName = fieldNameToLowerCamelCase(proto.getName());
+        jsonName = fieldNameToJsonName(proto.getName());
       }
 
       if (proto.hasType()) {
@@ -1466,8 +1501,8 @@
      * For internal use only.  This is to satisfy the FieldDescriptorLite
      * interface.
      */
-    public MessageLite.Builder internalMergeFrom(
-        MessageLite.Builder to, MessageLite from) {
+    @Override
+    public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
       // FieldDescriptors are only used with non-lite messages so we can just
       // down-cast and call mergeFrom directly.
       return ((Message.Builder) to).mergeFrom((Message) from);
@@ -1487,19 +1522,31 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public EnumDescriptorProto toProto() { return proto; }
+    @Override
+    public EnumDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /**
      * Get the type's fully-qualified name.
      * @see Descriptors.Descriptor#getFullName()
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** If this is a nested type, get the outer descriptor, otherwise null. */
     public Descriptor getContainingType() { return containingType; }
@@ -1533,6 +1580,7 @@
      * @param number The value's number.
      * @return the value's descriptor, or {@code null} if not found.
      */
+    @Override
     public EnumValueDescriptor findValueByNumber(final int number) {
       return file.pool.enumValuesByNumber.get(
         new DescriptorPool.DescriptorIntPair(this, number));
@@ -1659,13 +1707,22 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public EnumValueDescriptorProto toProto() { return proto; }
+    @Override
+    public EnumValueDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the value's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /** Get the value's number. */
-    public int getNumber() { return proto.getNumber(); }
+    @Override
+    public int getNumber() {
+      return proto.getNumber();
+    }
 
     @Override
     public String toString() { return proto.getName(); }
@@ -1674,10 +1731,16 @@
      * Get the value's fully-qualified name.
      * @see Descriptors.Descriptor#getFullName()
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** Get the value's enum type. */
     public EnumDescriptor getType() { return type; }
@@ -1745,19 +1808,31 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public ServiceDescriptorProto toProto() { return proto; }
+    @Override
+    public ServiceDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /**
      * Get the type's fully-qualified name.
      * @see Descriptors.Descriptor#getFullName()
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
     public ServiceOptions getOptions() { return proto.getOptions(); }
@@ -1835,19 +1910,31 @@
     public int getIndex() { return index; }
 
     /** Convert the descriptor to its protocol message representation. */
-    public MethodDescriptorProto toProto() { return proto; }
+    @Override
+    public MethodDescriptorProto toProto() {
+      return proto;
+    }
 
     /** Get the method's unqualified name. */
-    public String getName() { return proto.getName(); }
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
 
     /**
      * Get the method's fully-qualified name.
      * @see Descriptors.Descriptor#getFullName()
      */
-    public String getFullName() { return fullName; }
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
 
     /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
 
     /** Get the method's service type. */
     public ServiceDescriptor getService() { return service; }
@@ -2035,7 +2122,7 @@
           // Can't happen, because addPackage() only fails when the name
           // conflicts with a non-package, but we have not yet added any
           // non-packages at this point.
-          assert false;
+          throw new AssertionError(e);
         }
       }
     }
@@ -2248,10 +2335,22 @@
      * that has the same name as an existing package.
      */
     private static final class PackageDescriptor extends GenericDescriptor {
-      public Message toProto()        { return file.toProto(); }
-      public String getName()         { return name;           }
-      public String getFullName()     { return fullName;       }
-      public FileDescriptor getFile() { return file;           }
+      @Override
+      public Message toProto() {
+        return file.toProto();
+      }
+      @Override
+      public String getName() {
+        return name;
+      }
+      @Override
+      public String getFullName() {
+        return fullName;
+      }
+      @Override
+      public FileDescriptor getFile() {
+        return file;
+      }
 
       PackageDescriptor(final String name, final String fullName,
                         final FileDescriptor file) {
@@ -2404,6 +2503,10 @@
 
     public int getFieldCount() { return fieldCount; }
 
+    public OneofOptions getOptions() {
+      return proto.getOptions();
+    }
+
     /** Get a list of this message type's fields. */
     public List<FieldDescriptor> getFields() {
       return Collections.unmodifiableList(Arrays.asList(fields));
@@ -2413,6 +2516,10 @@
       return fields[index];
     }
 
+    private void setProto(final OneofDescriptorProto proto) {
+      this.proto = proto;
+    }
+
     private OneofDescriptor(final OneofDescriptorProto proto,
                             final FileDescriptor file,
                             final Descriptor parent,
diff --git a/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
new file mode 100644
index 0000000..7ae9434
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
@@ -0,0 +1,71 @@
+// 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;
+
+/**
+ * Parsers to discard unknown fields during parsing.
+ */
+public final class DiscardUnknownFieldsParser {
+
+  /**
+   * Warps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
+   * parsing.
+   *
+   * <p>Usage example:
+   * <pre>{@code
+     * private final static Parser<Foo> FOO_PARSER = DiscardUnknownFieldsParser.wrap(Foo.parser());
+     * Foo parseFooDiscardUnknown(ByteBuffer input) throws IOException {
+     *   return FOO_PARSER.parseFrom(input);
+     * }
+   * }</pre>
+   *
+   * <p>Like all other implementations of {@code Parser}, this parser is stateless and thread-safe.
+   *
+   * @param parser The delegated parser that parses messages.
+   * @return a {@link Parser} that will discard unknown fields during parsing.
+   */
+  public static final <T extends Message> Parser<T> wrap(final Parser<T> parser) {
+    return new AbstractParser<T>() {
+      @Override
+      public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+        try {
+          input.discardUnknownFields();
+          return parser.parsePartialFrom(input, extensionRegistry);
+        } finally {
+          input.unsetDiscardUnknownFields();
+        }
+      }
+    };
+  }
+
+  private DiscardUnknownFieldsParser() {}
+}
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index bcc9d6e..5b28b4a 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -30,37 +30,35 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.DoubleList;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.DoubleList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.RandomAccess;
 
 /**
  * An implementation of {@link DoubleList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class DoubleArrayList
-    extends AbstractProtobufList<Double> implements DoubleList, RandomAccess {
-  
-  private static final int DEFAULT_CAPACITY = 10;
-  
+final class DoubleArrayList extends AbstractProtobufList<Double>
+    implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
+
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static DoubleArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private double[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -71,34 +69,71 @@
    * Constructs a new mutable {@code DoubleArrayList} with default capacity.
    */
   DoubleArrayList() {
-    this(DEFAULT_CAPACITY);
+    this(new double[DEFAULT_CAPACITY], 0);
   }
 
   /**
-   * Constructs a new mutable {@code DoubleArrayList} with the provided capacity.
+   * Constructs a new mutable {@code DoubleArrayList}
+   * containing the same elements as {@code other}.
    */
-  DoubleArrayList(int capacity) {
-    array = new double[capacity];
-    size = 0;
+  private DoubleArrayList(double[] other, int size) {
+    array = other;
+    this.size = size;
   }
 
-  /**
-   * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
-   */
-  DoubleArrayList(List<Double> other) {
-    if (other instanceof DoubleArrayList) {
-      DoubleArrayList list = (DoubleArrayList) other;
-      array = list.array.clone();
-      size = list.size;
-    } else {
-      size = other.size();
-      array = new double[size];
-      for (int i = 0; i < size; i++) {
-        array[i] = other.get(i);
+  @Override
+  protected void removeRange(int fromIndex, int toIndex) {
+    ensureIsMutable();
+    if (toIndex < fromIndex) {
+      throw new IndexOutOfBoundsException("toIndex < fromIndex");
+    }
+
+    System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+    size -= (toIndex - fromIndex);
+    modCount++;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof DoubleArrayList)) {
+      return super.equals(o);
+    }
+    DoubleArrayList other = (DoubleArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+
+    final double[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
       }
     }
+
+    return true;
   }
-  
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      long bits = Double.doubleToLongBits(array[i]);
+      result = (31 * result) + Internal.hashLong(bits);
+    }
+    return result;
+  }
+
+  @Override
+  public DoubleList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
   @Override
   public Double get(int index) {
     return getDouble(index);
@@ -150,7 +185,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -158,10 +193,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       double[] newArray = new double[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -175,38 +210,36 @@
   @Override
   public boolean addAll(Collection<? extends Double> collection) {
     ensureIsMutable();
-    
-    if (collection == null) {
-      throw new NullPointerException();
-    }
-    
+
+    checkNotNull(collection);
+
     // We specialize when adding another DoubleArrayList to avoid boxing elements.
     if (!(collection instanceof DoubleArrayList)) {
       return super.addAll(collection);
     }
-    
+
     DoubleArrayList list = (DoubleArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -226,7 +259,9 @@
     ensureIsMutable();
     ensureIndexInRange(index);
     double value = array[index];
-    System.arraycopy(array, index + 1, array, index, size - index);
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index);
+    }
     size--;
     modCount++;
     return value;
@@ -235,7 +270,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index 3ea1b68..a6a774b 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -30,11 +30,12 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.Internal.checkNotNull;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
@@ -156,18 +157,22 @@
   // -----------------------------------------------------------------
   // Implementation of Message interface.
 
+  @Override
   public Descriptor getDescriptorForType() {
     return type;
   }
 
+  @Override
   public DynamicMessage getDefaultInstanceForType() {
     return getDefaultInstance(type);
   }
 
+  @Override
   public Map<FieldDescriptor, Object> getAllFields() {
     return fields.getAllFields();
   }
 
+  @Override
   public boolean hasOneof(OneofDescriptor oneof) {
     verifyOneofContainingType(oneof);
     FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -177,16 +182,19 @@
     return true;
   }
 
+  @Override
   public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
     verifyOneofContainingType(oneof);
     return oneofCases[oneof.getIndex()];
   }
 
+  @Override
   public boolean hasField(FieldDescriptor field) {
     verifyContainingType(field);
     return fields.hasField(field);
   }
 
+  @Override
   public Object getField(FieldDescriptor field) {
     verifyContainingType(field);
     Object result = fields.getField(field);
@@ -202,16 +210,19 @@
     return result;
   }
 
+  @Override
   public int getRepeatedFieldCount(FieldDescriptor field) {
     verifyContainingType(field);
     return fields.getRepeatedFieldCount(field);
   }
 
+  @Override
   public Object getRepeatedField(FieldDescriptor field, int index) {
     verifyContainingType(field);
     return fields.getRepeatedField(field, index);
   }
 
+  @Override
   public UnknownFieldSet getUnknownFields() {
     return unknownFields;
   }
@@ -264,19 +275,22 @@
     return size;
   }
 
+  @Override
   public Builder newBuilderForType() {
     return new Builder(type);
   }
 
+  @Override
   public Builder toBuilder() {
     return newBuilderForType().mergeFrom(this);
   }
 
+  @Override
   public Parser<DynamicMessage> getParserForType() {
     return new AbstractParser<DynamicMessage>() {
+      @Override
       public DynamicMessage parsePartialFrom(
-          CodedInputStream input,
-          ExtensionRegistryLite extensionRegistry)
+          CodedInputStream input, ExtensionRegistryLite extensionRegistry)
           throws InvalidProtocolBufferException {
         Builder builder = newBuilder(type);
         try {
@@ -284,7 +298,7 @@
         } catch (InvalidProtocolBufferException e) {
           throw e.setUnfinishedMessage(builder.buildPartial());
         } catch (IOException e) {
-          throw new InvalidProtocolBufferException(e.getMessage())
+          throw new InvalidProtocolBufferException(e)
               .setUnfinishedMessage(builder.buildPartial());
         }
         return builder.buildPartial();
@@ -325,6 +339,20 @@
       this.fields = FieldSet.newFieldSet();
       this.unknownFields = UnknownFieldSet.getDefaultInstance();
       this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
+      // A MapEntry has all of its fields present at all times.
+      if (type.getOptions().getMapEntry()) {
+        populateMapEntry();
+      }
+    }
+
+    private void populateMapEntry() {
+      for (FieldDescriptor field : type.getFields()) {
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          fields.setField(field, getDefaultInstance(field.getMessageType()));
+        } else {
+          fields.setField(field, field.getDefaultValue());
+        }
+      }
     }
 
     // ---------------------------------------------------------------
@@ -337,6 +365,10 @@
       } else {
         fields.clear();
       }
+      // A MapEntry has all of its fields present at all times.
+      if (type.getOptions().getMapEntry()) {
+        populateMapEntry();
+      }
       unknownFields = UnknownFieldSet.getDefaultInstance();
       return this;
     }
@@ -370,6 +402,7 @@
       }
     }
 
+    @Override
     public DynamicMessage build() {
       if (!isInitialized()) {
         throw newUninitializedMessageException(
@@ -394,6 +427,7 @@
       return buildPartial();
     }
 
+    @Override
     public DynamicMessage buildPartial() {
       fields.makeImmutable();
       DynamicMessage result =
@@ -411,22 +445,27 @@
       return result;
     }
 
+    @Override
     public boolean isInitialized() {
       return DynamicMessage.isInitialized(type, fields);
     }
 
+    @Override
     public Descriptor getDescriptorForType() {
       return type;
     }
 
+    @Override
     public DynamicMessage getDefaultInstanceForType() {
       return getDefaultInstance(type);
     }
 
+    @Override
     public Map<FieldDescriptor, Object> getAllFields() {
       return fields.getAllFields();
     }
 
+    @Override
     public Builder newBuilderForField(FieldDescriptor field) {
       verifyContainingType(field);
 
@@ -438,6 +477,7 @@
       return new Builder(field.getMessageType());
     }
 
+    @Override
     public boolean hasOneof(OneofDescriptor oneof) {
       verifyOneofContainingType(oneof);
       FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -447,11 +487,13 @@
       return true;
     }
 
+    @Override
     public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
       verifyOneofContainingType(oneof);
       return oneofCases[oneof.getIndex()];
     }
 
+    @Override
     public Builder clearOneof(OneofDescriptor oneof) {
       verifyOneofContainingType(oneof);
       FieldDescriptor field = oneofCases[oneof.getIndex()];
@@ -461,11 +503,13 @@
       return this;
     }
 
+    @Override
     public boolean hasField(FieldDescriptor field) {
       verifyContainingType(field);
       return fields.hasField(field);
     }
 
+    @Override
     public Object getField(FieldDescriptor field) {
       verifyContainingType(field);
       Object result = fields.getField(field);
@@ -481,6 +525,7 @@
       return result;
     }
 
+    @Override
     public Builder setField(FieldDescriptor field, Object value) {
       verifyContainingType(field);
       ensureIsMutable();
@@ -500,11 +545,20 @@
           fields.clearField(oldField);
         }
         oneofCases[index] = field;
+      } else if (field.getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) {
+        if (!field.isRepeated()
+            && field.getJavaType() != FieldDescriptor.JavaType.MESSAGE
+            && value.equals(field.getDefaultValue())) {
+          // In proto3, setting a field to its default value is equivalent to clearing the field.
+          fields.clearField(field);
+          return this;
+        }
       }
       fields.setField(field, value);
       return this;
     }
 
+    @Override
     public Builder clearField(FieldDescriptor field) {
       verifyContainingType(field);
       ensureIsMutable();
@@ -519,24 +573,27 @@
       return this;
     }
 
+    @Override
     public int getRepeatedFieldCount(FieldDescriptor field) {
       verifyContainingType(field);
       return fields.getRepeatedFieldCount(field);
     }
 
+    @Override
     public Object getRepeatedField(FieldDescriptor field, int index) {
       verifyContainingType(field);
       return fields.getRepeatedField(field, index);
     }
 
-    public Builder setRepeatedField(FieldDescriptor field,
-                                    int index, Object value) {
+    @Override
+    public Builder setRepeatedField(FieldDescriptor field, int index, Object value) {
       verifyContainingType(field);
       ensureIsMutable();
       fields.setRepeatedField(field, index, value);
       return this;
     }
 
+    @Override
     public Builder addRepeatedField(FieldDescriptor field, Object value) {
       verifyContainingType(field);
       ensureIsMutable();
@@ -544,14 +601,15 @@
       return this;
     }
 
+    @Override
     public UnknownFieldSet getUnknownFields() {
       return unknownFields;
     }
 
+    @Override
     public Builder setUnknownFields(UnknownFieldSet unknownFields) {
-      if (getDescriptorForType().getFile().getSyntax()
-          == Descriptors.FileDescriptor.Syntax.PROTO3) {
-        // Proto3 discards unknown fields.
+      if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
+          && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
         return this;
       }
       this.unknownFields = unknownFields;
@@ -560,9 +618,8 @@
 
     @Override
     public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
-      if (getDescriptorForType().getFile().getSyntax()
-          == Descriptors.FileDescriptor.Syntax.PROTO3) {
-        // Proto3 discards unknown fields.
+      if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
+          && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
         return this;
       }
       this.unknownFields =
@@ -591,9 +648,7 @@
     /** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
     private void ensureSingularEnumValueDescriptor(
         FieldDescriptor field, Object value) {
-      if (value == null) {
-        throw new NullPointerException();
-      }
+      checkNotNull(value);
       if (!(value instanceof EnumValueDescriptor)) {
         throw new IllegalArgumentException(
           "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
diff --git a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
index 6f41fb8..3cd4c88 100644
--- a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
+++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
@@ -1,3 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 package com.google.protobuf;
 
 import java.lang.annotation.Documented;
diff --git a/java/core/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
index 68d29f3..5df12e6 100644
--- a/java/core/src/main/java/com/google/protobuf/Extension.java
+++ b/java/core/src/main/java/com/google/protobuf/Extension.java
@@ -42,6 +42,7 @@
   public abstract Descriptors.FieldDescriptor getDescriptor();
 
   /** Returns whether or not this extension is a Lite Extension. */
+  @Override
   final boolean isLite() {
     return false;
   }
@@ -57,10 +58,7 @@
     PROTO1,
   }
 
-  protected ExtensionType getExtensionType() {
-    // TODO(liujisi): make this abstract after we fix proto1.
-    return ExtensionType.IMMUTABLE;
-  }
+  protected abstract ExtensionType getExtensionType();
 
   /**
    * Type of a message extension.
@@ -69,7 +67,7 @@
     PROTO1,
     PROTO2,
   }
-  
+
   /**
    * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
    * returns the type of the message, otherwise undefined.
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
index 0067392..a22a74a 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -32,7 +32,6 @@
 
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -101,7 +100,7 @@
 
   /** Get the unmodifiable singleton empty instance. */
   public static ExtensionRegistry getEmptyRegistry() {
-    return EMPTY;
+    return EMPTY_REGISTRY;
   }
 
 
@@ -243,6 +242,11 @@
     add(newExtensionInfo(extension), extension.getExtensionType());
   }
 
+  /** Add an extension from a generated file to the registry. */
+  public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
+    add((Extension<?, ?>) extension);
+  }
+
   static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
     if (extension.getDescriptor().getJavaType() ==
         FieldDescriptor.JavaType.MESSAGE) {
@@ -311,7 +315,7 @@
   private final Map<DescriptorIntPair, ExtensionInfo> mutableExtensionsByNumber;
 
   ExtensionRegistry(boolean empty) {
-    super(ExtensionRegistryLite.getEmptyRegistry());
+    super(EMPTY_REGISTRY_LITE);
     this.immutableExtensionsByName =
         Collections.<String, ExtensionInfo>emptyMap();
     this.mutableExtensionsByName =
@@ -321,7 +325,7 @@
     this.mutableExtensionsByNumber =
             Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
   }
-  private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
+  static final ExtensionRegistry EMPTY_REGISTRY = new ExtensionRegistry(true);
 
   private void add(
       final ExtensionInfo extension,
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
new file mode 100644
index 0000000..89f7ab9
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.ExtensionRegistryLite.EMPTY_REGISTRY_LITE;
+
+/**
+ * A factory object to create instances of {@link ExtensionRegistryLite}.
+ *
+ * <p>
+ * This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries
+ * are available, and if so, the instances returned are actually {@link ExtensionRegistry}.
+ */
+final class ExtensionRegistryFactory {
+
+  static final String FULL_REGISTRY_CLASS_NAME = "com.google.protobuf.ExtensionRegistry";
+
+  /* Visible for Testing
+     @Nullable */
+  static final Class<?> EXTENSION_REGISTRY_CLASS = reflectExtensionRegistry();
+
+  /* @Nullable */
+  static Class<?> reflectExtensionRegistry() {
+    try {
+      return Class.forName(FULL_REGISTRY_CLASS_NAME);
+    } catch (ClassNotFoundException e) {
+      // The exception allocation is potentially expensive on Android (where it can be triggered
+      // many times at start up). Is there a way to ameliorate this?
+      return null;
+    }
+  }
+
+  /** Construct a new, empty instance. */
+  public static ExtensionRegistryLite create() {
+    if (EXTENSION_REGISTRY_CLASS != null) {
+      try {
+        return invokeSubclassFactory("newInstance");
+      } catch (Exception e) {
+        // return a Lite registry.
+      }
+    }
+    return new ExtensionRegistryLite();
+  }
+
+  /** Get the unmodifiable singleton empty instance. */
+  public static ExtensionRegistryLite createEmpty() {
+    if (EXTENSION_REGISTRY_CLASS != null) {
+      try {
+        return invokeSubclassFactory("getEmptyRegistry");
+      } catch (Exception e) {
+        // return a Lite registry.
+      }
+    }
+    return EMPTY_REGISTRY_LITE;
+  }
+
+
+  static boolean isFullRegistry(ExtensionRegistryLite registry) {
+    return EXTENSION_REGISTRY_CLASS != null
+        && EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
+  }
+
+  private static final ExtensionRegistryLite invokeSubclassFactory(String methodName)
+      throws Exception {
+    return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS
+        .getDeclaredMethod(methodName).invoke(null);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
index 65cf738..f3d48d3 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
@@ -79,6 +79,22 @@
   // applications. Need to support this feature on smaller granularity.
   private static volatile boolean eagerlyParseMessageSets = false;
 
+  // Visible for testing.
+  static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
+
+  /* @Nullable */
+  static Class<?> resolveExtensionClass() {
+    try {
+      return Class.forName(EXTENSION_CLASS_NAME);
+    } catch (ClassNotFoundException e) {
+      // See comment in ExtensionRegistryFactory on the potential expense of this.
+      return null;
+    }
+  }
+
+  /* @Nullable */
+  private static final Class<?> extensionClass = resolveExtensionClass();
+
   public static boolean isEagerlyParseMessageSets() {
     return eagerlyParseMessageSets;
   }
@@ -87,16 +103,25 @@
     eagerlyParseMessageSets = isEagerlyParse;
   }
 
-  /** Construct a new, empty instance. */
+  /**
+   * Construct a new, empty instance.
+   *
+   * <p>This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are
+   * available.
+   */
   public static ExtensionRegistryLite newInstance() {
-    return new ExtensionRegistryLite();
+    return ExtensionRegistryFactory.create();
   }
 
-  /** Get the unmodifiable singleton empty instance. */
+  /**
+   * Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or
+   * {@code ExtensionRegistry} (if the full (non-Lite) proto libraries are available).
+   */
   public static ExtensionRegistryLite getEmptyRegistry() {
-    return EMPTY;
+    return ExtensionRegistryFactory.createEmpty();
   }
 
+
   /** Returns an unmodifiable view of the registry. */
   public ExtensionRegistryLite getUnmodifiable() {
     return new ExtensionRegistryLite(this);
@@ -128,6 +153,23 @@
       extension);
   }
 
+  /**
+   * Add an extension from a lite generated file to the registry only if it is
+   * a non-lite extension i.e. {@link GeneratedMessageLite.GeneratedExtension}. */
+  public final void add(ExtensionLite<?, ?> extension) {
+    if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
+      add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
+    }
+    if (ExtensionRegistryFactory.isFullRegistry(this)) {
+      try {
+        this.getClass().getMethod("add", extensionClass).invoke(this, extension);
+      } catch (Exception e) {
+        throw new IllegalArgumentException(
+            String.format("Could not invoke ExtensionRegistry#add for %s", extension), e);
+      }
+    }
+  }
+
   // =================================================================
   // Private stuff.
 
@@ -139,9 +181,11 @@
         new HashMap<ObjectIntPair,
                     GeneratedMessageLite.GeneratedExtension<?, ?>>();
   }
+  static final ExtensionRegistryLite EMPTY_REGISTRY_LITE =
+      new ExtensionRegistryLite(true);
 
   ExtensionRegistryLite(ExtensionRegistryLite other) {
-    if (other == EMPTY) {
+    if (other == EMPTY_REGISTRY_LITE) {
       this.extensionsByNumber = Collections.emptyMap();
     } else {
       this.extensionsByNumber =
@@ -153,11 +197,9 @@
                     GeneratedMessageLite.GeneratedExtension<?, ?>>
       extensionsByNumber;
 
-  private ExtensionRegistryLite(boolean empty) {
+  ExtensionRegistryLite(boolean empty) {
     this.extensionsByNumber = Collections.emptyMap();
   }
-  private static final ExtensionRegistryLite EMPTY =
-    new ExtensionRegistryLite(true);
 
   /** A (Object, int) pair, used as a map key. */
   private static final class ObjectIntPair {
diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
index 47924b6..c09daa3 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -30,8 +30,9 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.LazyField.LazyIterator;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.LazyField.LazyIterator;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -101,6 +102,11 @@
   @SuppressWarnings("rawtypes")
   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
 
+  /** Returns {@code true} if empty, {@code false} otherwise. */
+  boolean isEmpty() {
+    return fields.isEmpty();
+  }
+
   /** Make this FieldSet immutable from this point forward. */
   @SuppressWarnings("unchecked")
   public void makeImmutable() {
@@ -121,6 +127,25 @@
     return isImmutable;
   }
 
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+
+    if (!(o instanceof FieldSet)) {
+      return false;
+    }
+
+    FieldSet<?> other = (FieldSet<?>) o;
+    return fields.equals(other.fields);
+  }
+
+  @Override
+  public int hashCode() {
+    return fields.hashCode();
+  }
+
   /**
    * Clones the FieldSet. The returned FieldSet will be mutable even if the
    * original FieldSet was immutable.
@@ -201,6 +226,7 @@
     return fields.entrySet().iterator();
   }
 
+
   /**
    * Useful for implementing
    * {@link Message#hasField(Descriptors.FieldDescriptor)}.
@@ -365,9 +391,7 @@
    */
   private static void verifyType(final WireFormat.FieldType type,
                                  final Object value) {
-    if (value == null) {
-      throw new NullPointerException();
-    }
+    checkNotNull(value);
 
     boolean isValid = false;
     switch (type.getJavaType()) {
@@ -474,7 +498,7 @@
   }
 
   /**
-   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 
+   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
    * {@link FieldSet}.
    */
   public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
@@ -619,10 +643,11 @@
    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
    *               this field.
    */
-  private static void writeElement(final CodedOutputStream output,
-                                   final WireFormat.FieldType type,
-                                   final int number,
-                                   final Object value) throws IOException {
+  static void writeElement(
+      final CodedOutputStream output,
+      final WireFormat.FieldType type,
+      final int number,
+      final Object value) throws IOException {
     // Special case for groups, which need a start and end tag; other fields
     // can just use writeTag() and writeFieldNoTag().
     if (type == WireFormat.FieldType.GROUP) {
@@ -785,9 +810,8 @@
    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
    *               this field.
    */
-  private static int computeElementSize(
-      final WireFormat.FieldType type,
-      final int number, final Object value) {
+  static int computeElementSize(
+      final WireFormat.FieldType type, final int number, final Object value) {
     int tagSize = CodedOutputStream.computeTagSize(number);
     if (type == WireFormat.FieldType.GROUP) {
       // Only count the end group tag for proto2 messages as for proto1 the end
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 033b5ee..7c080af 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -30,36 +30,35 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.FloatList;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.FloatList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.RandomAccess;
 
 /**
  * An implementation of {@link FloatList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class FloatArrayList extends AbstractProtobufList<Float> implements FloatList, RandomAccess {
-  
-  private static final int DEFAULT_CAPACITY = 10;
-  
+final class FloatArrayList extends AbstractProtobufList<Float>
+    implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
+
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static FloatArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private float[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -70,34 +69,70 @@
    * Constructs a new mutable {@code FloatArrayList} with default capacity.
    */
   FloatArrayList() {
-    this(DEFAULT_CAPACITY);
+    this(new float[DEFAULT_CAPACITY], 0);
   }
 
   /**
-   * Constructs a new mutable {@code FloatArrayList} with the provided capacity.
+   * Constructs a new mutable {@code FloatArrayList}
+   * containing the same elements as {@code other}.
    */
-  FloatArrayList(int capacity) {
-    array = new float[capacity];
-    size = 0;
+  private FloatArrayList(float[] other, int size) {
+    array = other;
+    this.size = size;
   }
 
-  /**
-   * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
-   */
-  FloatArrayList(List<Float> other) {
-    if (other instanceof FloatArrayList) {
-      FloatArrayList list = (FloatArrayList) other;
-      array = list.array.clone();
-      size = list.size;
-    } else {
-      size = other.size();
-      array = new float[size];
-      for (int i = 0; i < size; i++) {
-        array[i] = other.get(i);
+  @Override
+  protected void removeRange(int fromIndex, int toIndex) {
+    ensureIsMutable();
+    if (toIndex < fromIndex) {
+      throw new IndexOutOfBoundsException("toIndex < fromIndex");
+    }
+
+    System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+    size -= (toIndex - fromIndex);
+    modCount++;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof FloatArrayList)) {
+      return super.equals(o);
+    }
+    FloatArrayList other = (FloatArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+
+    final float[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
       }
     }
+
+    return true;
   }
-  
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Float.floatToIntBits(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public FloatList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new FloatArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
   @Override
   public Float get(int index) {
     return getFloat(index);
@@ -149,7 +184,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -157,10 +192,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       float[] newArray = new float[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -174,38 +209,36 @@
   @Override
   public boolean addAll(Collection<? extends Float> collection) {
     ensureIsMutable();
-    
-    if (collection == null) {
-      throw new NullPointerException();
-    }
-    
+
+    checkNotNull(collection);
+
     // We specialize when adding another FloatArrayList to avoid boxing elements.
     if (!(collection instanceof FloatArrayList)) {
       return super.addAll(collection);
     }
-    
+
     FloatArrayList list = (FloatArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -225,7 +258,9 @@
     ensureIsMutable();
     ensureIndexInRange(index);
     float value = array[index];
-    System.arraycopy(array, index + 1, array, index, size - index);
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index);
+    }
     size--;
     modCount++;
     return value;
@@ -234,7 +269,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index ceb97a4..60179e3 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -80,6 +80,7 @@
     unknownFields = builder.getUnknownFields();
   }
 
+  @Override
   public Parser<? extends GeneratedMessage> getParserForType() {
     throw new UnsupportedOperationException(
         "This is supposed to be overridden by subclasses.");
@@ -102,7 +103,7 @@
    */
   protected abstract FieldAccessorTable internalGetFieldAccessorTable();
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public Descriptor getDescriptorForType() {
     return internalGetFieldAccessorTable().descriptor;
   }
@@ -191,7 +192,7 @@
     return true;
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public Map<FieldDescriptor, Object> getAllFields() {
     return Collections.unmodifiableMap(
         getAllFieldsMutable(/* getBytesForString = */ false));
@@ -212,22 +213,22 @@
         getAllFieldsMutable(/* getBytesForString = */ true));
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public boolean hasOneof(final OneofDescriptor oneof) {
     return internalGetFieldAccessorTable().getOneof(oneof).has(this);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
     return internalGetFieldAccessorTable().getOneof(oneof).get(this);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public boolean hasField(final FieldDescriptor field) {
     return internalGetFieldAccessorTable().getField(field).has(this);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public Object getField(final FieldDescriptor field) {
     return internalGetFieldAccessorTable().getField(field).get(this);
   }
@@ -244,19 +245,19 @@
     return internalGetFieldAccessorTable().getField(field).getRaw(this);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public int getRepeatedFieldCount(final FieldDescriptor field) {
     return internalGetFieldAccessorTable().getField(field)
       .getRepeatedCount(this);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public Object getRepeatedField(final FieldDescriptor field, final int index) {
     return internalGetFieldAccessorTable().getField(field)
       .getRepeated(this, index);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public UnknownFieldSet getUnknownFields() {
     throw new UnsupportedOperationException(
         "This is supposed to be overridden by subclasses.");
@@ -354,33 +355,32 @@
     // Noop for messages without extensions.
   }
 
-  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
+  /**
+   * TODO(xiaofeng): remove this after b/29368482 is fixed. We need to move this
+   * interface to AbstractMessage in order to versioning GeneratedMessage but
+   * this move breaks binary compatibility for AppEngine. After AppEngine is
+   * fixed we can exlude this from google3.
+   */
+  protected interface BuilderParent extends AbstractMessage.BuilderParent {}
 
   /**
-   * Interface for the parent of a Builder that allows the builder to
-   * communicate invalidations back to the parent for use when using nested
-   * builders.
+   * TODO(xiaofeng): remove this together with GeneratedMessage.BuilderParent.
    */
-  protected interface BuilderParent {
+  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
 
-    /**
-     * A builder becomes dirty whenever a field is modified -- including fields
-     * in nested builders -- and becomes clean when build() is called.  Thus,
-     * when a builder becomes dirty, all its parents become dirty as well, and
-     * when it becomes clean, all its children become clean.  The dirtiness
-     * state is used to invalidate certain cached values.
-     * <br>
-     * To this end, a builder calls markAsDirty() on its parent whenever it
-     * transitions from clean to dirty.  The parent must propagate this call to
-     * its own parent, unless it was already dirty, in which case the
-     * grandparent must necessarily already be dirty as well.  The parent can
-     * only transition back to "clean" after calling build() on all children.
-     */
-    void markDirty();
+  @Override
+  protected Message.Builder newBuilderForType(final AbstractMessage.BuilderParent parent) {
+    return newBuilderForType(new BuilderParent() {
+      @Override
+      public void markDirty() {
+        parent.markDirty();
+      }
+    });
   }
 
+
   @SuppressWarnings("unchecked")
-  public abstract static class Builder <BuilderType extends Builder>
+  public abstract static class Builder <BuilderType extends Builder<BuilderType>>
       extends AbstractMessage.Builder<BuilderType> {
 
     private BuilderParent builderParent;
@@ -402,6 +402,7 @@
       this.builderParent = builderParent;
     }
 
+    @Override
     void dispose() {
       builderParent = null;
     }
@@ -419,6 +420,7 @@
      * Called by the subclass or a builder to notify us that a message was
      * built and may be cached and therefore invalidations are needed.
      */
+    @Override
     protected void markClean() {
       this.isClean = true;
     }
@@ -444,6 +446,7 @@
      * Called by the initialization and clear code paths to allow subclasses to
      * reset any of their builtin fields back to the initial values.
      */
+    @Override
     public BuilderType clear() {
       unknownFields = UnknownFieldSet.getDefaultInstance();
       onChanged();
@@ -457,12 +460,12 @@
      */
     protected abstract FieldAccessorTable internalGetFieldAccessorTable();
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public Descriptor getDescriptorForType() {
       return internalGetFieldAccessorTable().descriptor;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public Map<FieldDescriptor, Object> getAllFields() {
       return Collections.unmodifiableMap(getAllFieldsMutable());
     }
@@ -510,39 +513,38 @@
       return result;
     }
 
-    public Message.Builder newBuilderForField(
-        final FieldDescriptor field) {
+    @Override
+    public Message.Builder newBuilderForField(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field).newBuilder();
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public Message.Builder getFieldBuilder(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field).getBuilder(this);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field,
-        int index) {
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
       return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
           this, index);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public boolean hasOneof(final OneofDescriptor oneof) {
       return internalGetFieldAccessorTable().getOneof(oneof).has(this);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
       return internalGetFieldAccessorTable().getOneof(oneof).get(this);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public boolean hasField(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field).has(this);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public Object getField(final FieldDescriptor field) {
       Object object = internalGetFieldAccessorTable().getField(field).get(this);
       if (field.isRepeated()) {
@@ -554,52 +556,52 @@
       }
     }
 
-    public BuilderType setField(final FieldDescriptor field,
-                                final Object value) {
+    @Override
+    public BuilderType setField(final FieldDescriptor field, final Object value) {
       internalGetFieldAccessorTable().getField(field).set(this, value);
       return (BuilderType) this;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public BuilderType clearField(final FieldDescriptor field) {
       internalGetFieldAccessorTable().getField(field).clear(this);
       return (BuilderType) this;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public BuilderType clearOneof(final OneofDescriptor oneof) {
       internalGetFieldAccessorTable().getOneof(oneof).clear(this);
       return (BuilderType) this;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public int getRepeatedFieldCount(final FieldDescriptor field) {
       return internalGetFieldAccessorTable().getField(field)
           .getRepeatedCount(this);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Object getRepeatedField(final FieldDescriptor field,
-                                   final int index) {
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field, final int index) {
       return internalGetFieldAccessorTable().getField(field)
           .getRepeated(this, index);
     }
 
-    public BuilderType setRepeatedField(final FieldDescriptor field,
-                                        final int index, final Object value) {
+    @Override
+    public BuilderType setRepeatedField(
+        final FieldDescriptor field, final int index, final Object value) {
       internalGetFieldAccessorTable().getField(field)
         .setRepeated(this, index, value);
       return (BuilderType) this;
     }
 
-    public BuilderType addRepeatedField(final FieldDescriptor field,
-                                        final Object value) {
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
       internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
       return (BuilderType) this;
     }
 
-    public BuilderType setUnknownFields(
-        final UnknownFieldSet unknownFields) {
+    @Override
+    public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
       this.unknownFields = unknownFields;
       onChanged();
       return (BuilderType) this;
@@ -616,7 +618,7 @@
       return (BuilderType) this;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public boolean isInitialized() {
       for (final FieldDescriptor field : getDescriptorForType().getFields()) {
         // Check that all required fields are present.
@@ -646,7 +648,7 @@
       return true;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final UnknownFieldSet getUnknownFields() {
       return unknownFields;
     }
@@ -670,7 +672,7 @@
      */
     private class BuilderParentImpl implements BuilderParent {
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public void markDirty() {
         onChanged();
       }
@@ -735,6 +737,7 @@
   public interface ExtendableMessageOrBuilder<
       MessageType extends ExtendableMessage> extends MessageOrBuilder {
     // Re-define for return type covariance.
+    @Override
     Message getDefaultInstanceForType();
 
     /** Check if a singular extension is present. */
@@ -753,6 +756,33 @@
     <Type> Type getExtension(
         ExtensionLite<MessageType, List<Type>> extension,
         int index);
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        Extension<MessageType, Type> extension);
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        Extension<MessageType, List<Type>> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        GeneratedExtension<MessageType, List<Type>> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, Type> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, List<Type>> extension,
+        int index);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, List<Type>> extension,
+        int index);
   }
 
   /**
@@ -795,6 +825,8 @@
       extends GeneratedMessage
       implements ExtendableMessageOrBuilder<MessageType> {
 
+    private static final long serialVersionUID = 1L;
+
     private final FieldSet<FieldDescriptor> extensions;
 
     protected ExtendableMessage() {
@@ -821,9 +853,9 @@
     }
 
     /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final ExtensionLite<MessageType, Type> extensionLite) {
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
       Extension<MessageType, Type> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -831,7 +863,8 @@
     }
 
     /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
+    @SuppressWarnings("unchecked")
     public final <Type> int getExtensionCount(
         final ExtensionLite<MessageType, List<Type>> extensionLite) {
       Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -842,10 +875,9 @@
     }
 
     /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, Type> extensionLite) {
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
       Extension<MessageType, Type> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -867,11 +899,10 @@
     }
 
     /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, List<Type>> extensionLite,
-        final int index) {
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
       Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -880,6 +911,53 @@
           extensions.getRepeatedField(descriptor, index));
     }
 
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+
     /** Called by subclasses to check if all extensions are initialized. */
     protected boolean extensionsAreInitialized() {
       return extensions.isInitialized();
@@ -1019,7 +1097,9 @@
         verifyContainingType(field);
         final Object value = extensions.getField(field);
         if (value == null) {
-          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (field.isRepeated()) {
+            return Collections.emptyList();
+          } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
             // Lacking an ExtensionRegistry, we have no way to determine the
             // extension's real type, so we return a DynamicMessage.
             return DynamicMessage.getDefaultInstance(field.getMessageType());
@@ -1103,7 +1183,7 @@
   @SuppressWarnings("unchecked")
   public abstract static class ExtendableBuilder<
         MessageType extends ExtendableMessage,
-        BuilderType extends ExtendableBuilder>
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
       extends Builder<BuilderType>
       implements ExtendableMessageOrBuilder<MessageType> {
 
@@ -1155,9 +1235,8 @@
     }
 
     /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final ExtensionLite<MessageType, Type> extensionLite) {
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
       Extension<MessageType, Type> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -1165,7 +1244,7 @@
     }
 
     /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final <Type> int getExtensionCount(
         final ExtensionLite<MessageType, List<Type>> extensionLite) {
       Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@@ -1176,9 +1255,8 @@
     }
 
     /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, Type> extensionLite) {
+    @Override
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
       Extension<MessageType, Type> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -1200,10 +1278,9 @@
     }
 
     /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, List<Type>> extensionLite,
-        final int index) {
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
       Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
@@ -1269,6 +1346,95 @@
       return (BuilderType) this;
     }
 
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of an extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final Extension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Append a value to a repeated extension. */
+    public <Type> BuilderType addExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final Extension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+    /** Clear an extension. */
+    public <Type> BuilderType clearExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+
     /** Called by subclasses to check if all extensions are initialized. */
     protected boolean extensionsAreInitialized() {
       return extensions.isInitialized();
@@ -1456,10 +1622,9 @@
     // obtained.
     return new GeneratedExtension<ContainingType, Type>(
         new CachedDescriptorRetriever() {
-          //@Override (Java 1.6 override semantics, but we must support 1.5)
+          @Override
           public FieldDescriptor loadDescriptor() {
-            return scope.getDescriptorForType().getExtensions()
-                .get(descriptorIndex);
+            return scope.getDescriptorForType().getExtensions().get(descriptorIndex);
           }
         },
         singularType,
@@ -1487,6 +1652,7 @@
     private volatile FieldDescriptor descriptor;
     protected abstract FieldDescriptor loadDescriptor();
 
+    @Override
     public FieldDescriptor getDescriptor() {
       if (descriptor == null) {
         synchronized (this) {
@@ -1516,6 +1682,7 @@
     // obtained.
     return new GeneratedExtension<ContainingType, Type>(
         new CachedDescriptorRetriever() {
+          @Override
           protected FieldDescriptor loadDescriptor() {
             return scope.getDescriptorForType().findFieldByName(name);
           }
@@ -1542,17 +1709,18 @@
     // used to obtain the extension's FieldDescriptor.
     return new GeneratedExtension<ContainingType, Type>(
         new CachedDescriptorRetriever() {
+          @Override
           protected FieldDescriptor loadDescriptor() {
             try {
-              Class clazz =
-                  singularType.getClassLoader().loadClass(descriptorOuterClass);
-              FileDescriptor file =
-                  (FileDescriptor) clazz.getField("descriptor").get(null);
+              Class clazz = singularType.getClassLoader().loadClass(descriptorOuterClass);
+              FileDescriptor file = (FileDescriptor) clazz.getField("descriptor").get(null);
               return file.findExtensionByName(extensionName);
             } catch (Exception e) {
               throw new RuntimeException(
-                  "Cannot load descriptors: " + descriptorOuterClass +
-                  " is not a valid descriptor class name", e);
+                  "Cannot load descriptors: "
+                      + descriptorOuterClass
+                      + " is not a valid descriptor class name",
+                  e);
             }
           }
         },
@@ -1634,12 +1802,13 @@
       if (descriptorRetriever != null) {
         throw new IllegalStateException("Already initialized.");
       }
-      descriptorRetriever = new ExtensionDescriptorRetriever() {
-          //@Override (Java 1.6 override semantics, but we must support 1.5)
-          public FieldDescriptor getDescriptor() {
-            return descriptor;
-          }
-        };
+      descriptorRetriever =
+          new ExtensionDescriptorRetriever() {
+            @Override
+            public FieldDescriptor getDescriptor() {
+              return descriptor;
+            }
+          };
     }
 
     private ExtensionDescriptorRetriever descriptorRetriever;
@@ -1649,6 +1818,7 @@
     private final Method enumGetValueDescriptor;
     private final ExtensionType extensionType;
 
+    @Override
     public FieldDescriptor getDescriptor() {
       if (descriptorRetriever == null) {
         throw new IllegalStateException(
@@ -1661,10 +1831,12 @@
      * If the extension is an embedded message or group, returns the default
      * instance of the message.
      */
+    @Override
     public Message getMessageDefaultInstance() {
       return messageDefaultInstance;
     }
 
+    @Override
     protected ExtensionType getExtensionType() {
       return extensionType;
     }
@@ -1675,7 +1847,7 @@
      * EnumValueDescriptors but the native accessors use the generated enum
      * type.
      */
-    // @Override
+    @Override
     @SuppressWarnings("unchecked")
     protected Object fromReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
@@ -1700,7 +1872,7 @@
      * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
      * type, this converts a single element.
      */
-    // @Override
+    @Override
     protected Object singularFromReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       switch (descriptor.getJavaType()) {
@@ -1724,7 +1896,7 @@
      * EnumValueDescriptors but the native accessors use the generated enum
      * type.
      */
-    // @Override
+    @Override
     @SuppressWarnings("unchecked")
     protected Object toReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
@@ -1748,7 +1920,7 @@
      * Like {@link #toReflectionType(Object)}, but if the type is a repeated
      * type, this converts a single element.
      */
-    // @Override
+    @Override
     protected Object singularToReflectionType(final Object value) {
       FieldDescriptor descriptor = getDescriptor();
       switch (descriptor.getJavaType()) {
@@ -1759,22 +1931,22 @@
       }
     }
 
-    // @Override
+    @Override
     public int getNumber() {
       return getDescriptor().getNumber();
     }
 
-    // @Override
+    @Override
     public WireFormat.FieldType getLiteType() {
       return getDescriptor().getLiteType();
     }
 
-    // @Override
+    @Override
     public boolean isRepeated() {
       return getDescriptor().isRepeated();
     }
 
-    // @Override
+    @Override
     @SuppressWarnings("unchecked")
     public Type getDefaultValue() {
       if (isRepeated()) {
@@ -2124,49 +2296,57 @@
         return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
       }
 
+      @Override
       public Object get(final GeneratedMessage message) {
         return invokeOrDie(getMethod, message);
       }
+      @Override
       public Object get(GeneratedMessage.Builder builder) {
         return invokeOrDie(getMethodBuilder, builder);
       }
+      @Override
       public Object getRaw(final GeneratedMessage message) {
         return get(message);
       }
+      @Override
       public Object getRaw(GeneratedMessage.Builder builder) {
         return get(builder);
       }
+      @Override
       public void set(final Builder builder, final Object value) {
         invokeOrDie(setMethod, builder, value);
       }
-      public Object getRepeated(final GeneratedMessage message,
-                                final int index) {
+      @Override
+      public Object getRepeated(final GeneratedMessage message, final int index) {
         throw new UnsupportedOperationException(
           "getRepeatedField() called on a singular field.");
       }
-      public Object getRepeatedRaw(final GeneratedMessage message,
-                                final int index) {
+      @Override
+      public Object getRepeatedRaw(final GeneratedMessage message, final int index) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldRaw() called on a singular field.");
       }
+      @Override
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
         throw new UnsupportedOperationException(
           "getRepeatedField() called on a singular field.");
       }
-      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
-          int index) {
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldRaw() called on a singular field.");
       }
-      public void setRepeated(final Builder builder, final int index,
-          final Object value) {
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
         throw new UnsupportedOperationException(
           "setRepeatedField() called on a singular field.");
       }
+      @Override
       public void addRepeated(final Builder builder, final Object value) {
         throw new UnsupportedOperationException(
           "addRepeatedField() called on a singular field.");
       }
+      @Override
       public boolean has(final GeneratedMessage message) {
         if (!hasHasMethod) {
           if (isOneofField) {
@@ -2176,6 +2356,7 @@
         }
         return (Boolean) invokeOrDie(hasMethod, message);
       }
+      @Override
       public boolean has(GeneratedMessage.Builder builder) {
         if (!hasHasMethod) {
           if (isOneofField) {
@@ -2185,27 +2366,32 @@
         }
         return (Boolean) invokeOrDie(hasMethodBuilder, builder);
       }
+      @Override
       public int getRepeatedCount(final GeneratedMessage message) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldSize() called on a singular field.");
       }
+      @Override
       public int getRepeatedCount(GeneratedMessage.Builder builder) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldSize() called on a singular field.");
       }
+      @Override
       public void clear(final Builder builder) {
         invokeOrDie(clearMethod, builder);
       }
+      @Override
       public Message.Builder newBuilder() {
         throw new UnsupportedOperationException(
           "newBuilderForField() called on a non-Message type.");
       }
+      @Override
       public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
         throw new UnsupportedOperationException(
           "getFieldBuilder() called on a non-Message type.");
       }
-      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder,
-          int index) {
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldBuilder() called on a non-Message type.");
       }
@@ -2249,18 +2435,23 @@
         clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
       }
 
+      @Override
       public Object get(final GeneratedMessage message) {
         return invokeOrDie(getMethod, message);
       }
+      @Override
       public Object get(GeneratedMessage.Builder builder) {
         return invokeOrDie(getMethodBuilder, builder);
       }
+      @Override
       public Object getRaw(final GeneratedMessage message) {
         return get(message);
       }
+      @Override
       public Object getRaw(GeneratedMessage.Builder builder) {
         return get(builder);
       }
+      @Override
       public void set(final Builder builder, final Object value) {
         // Add all the elements individually.  This serves two purposes:
         // 1) Verifies that each element has the correct type.
@@ -2271,54 +2462,64 @@
           addRepeated(builder, element);
         }
       }
-      public Object getRepeated(final GeneratedMessage message,
-                                final int index) {
+      @Override
+      public Object getRepeated(final GeneratedMessage message, final int index) {
         return invokeOrDie(getRepeatedMethod, message, index);
       }
+      @Override
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
         return invokeOrDie(getRepeatedMethodBuilder, builder, index);
       }
+      @Override
       public Object getRepeatedRaw(GeneratedMessage message, int index) {
         return getRepeated(message, index);
       }
-      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
-          int index) {
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
         return getRepeated(builder, index);
       }
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
         invokeOrDie(setRepeatedMethod, builder, index, value);
       }
+      @Override
       public void addRepeated(final Builder builder, final Object value) {
         invokeOrDie(addRepeatedMethod, builder, value);
       }
+      @Override
       public boolean has(final GeneratedMessage message) {
         throw new UnsupportedOperationException(
           "hasField() called on a repeated field.");
       }
+      @Override
       public boolean has(GeneratedMessage.Builder builder) {
         throw new UnsupportedOperationException(
           "hasField() called on a repeated field.");
       }
+      @Override
       public int getRepeatedCount(final GeneratedMessage message) {
         return (Integer) invokeOrDie(getCountMethod, message);
       }
+      @Override
       public int getRepeatedCount(GeneratedMessage.Builder builder) {
         return (Integer) invokeOrDie(getCountMethodBuilder, builder);
       }
+      @Override
       public void clear(final Builder builder) {
         invokeOrDie(clearMethod, builder);
       }
+      @Override
       public Message.Builder newBuilder() {
         throw new UnsupportedOperationException(
           "newBuilderForField() called on a non-Message type.");
       }
+      @Override
       public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
         throw new UnsupportedOperationException(
           "getFieldBuilder() called on a non-Message type.");
       }
-      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder,
-          int index) {
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
         throw new UnsupportedOperationException(
           "getRepeatedFieldBuilder() called on a non-Message type.");
       }
@@ -2355,6 +2556,8 @@
             field.getNumber());
       }
 
+      @Override
+      @SuppressWarnings("unchecked")
       public Object get(GeneratedMessage message) {
         List result = new ArrayList();
         for (int i = 0; i < getRepeatedCount(message); i++) {
@@ -2363,6 +2566,8 @@
         return Collections.unmodifiableList(result);
       }
 
+      @Override
+      @SuppressWarnings("unchecked")
       public Object get(Builder builder) {
         List result = new ArrayList();
         for (int i = 0; i < getRepeatedCount(builder); i++) {
@@ -2371,14 +2576,17 @@
         return Collections.unmodifiableList(result);
       }
 
+      @Override
       public Object getRaw(GeneratedMessage message) {
         return get(message);
       }
 
+      @Override
       public Object getRaw(GeneratedMessage.Builder builder) {
         return get(builder);
       }
 
+      @Override
       public void set(Builder builder, Object value) {
         clear(builder);
         for (Object entry : (List) value) {
@@ -2386,63 +2594,76 @@
         }
       }
 
+      @Override
       public Object getRepeated(GeneratedMessage message, int index) {
         return getMapField(message).getList().get(index);
       }
 
+      @Override
       public Object getRepeated(Builder builder, int index) {
         return getMapField(builder).getList().get(index);
       }
 
+      @Override
       public Object getRepeatedRaw(GeneratedMessage message, int index) {
         return getRepeated(message, index);
       }
 
+      @Override
       public Object getRepeatedRaw(Builder builder, int index) {
         return getRepeated(builder, index);
       }
 
+      @Override
       public void setRepeated(Builder builder, int index, Object value) {
         getMutableMapField(builder).getMutableList().set(index, (Message) value);
       }
 
+      @Override
       public void addRepeated(Builder builder, Object value) {
         getMutableMapField(builder).getMutableList().add((Message) value);
       }
 
+      @Override
       public boolean has(GeneratedMessage message) {
         throw new UnsupportedOperationException(
             "hasField() is not supported for repeated fields.");
       }
 
+      @Override
       public boolean has(Builder builder) {
         throw new UnsupportedOperationException(
             "hasField() is not supported for repeated fields.");
       }
 
+      @Override
       public int getRepeatedCount(GeneratedMessage message) {
         return getMapField(message).getList().size();
       }
 
+      @Override
       public int getRepeatedCount(Builder builder) {
         return getMapField(builder).getList().size();
       }
 
+      @Override
       public void clear(Builder builder) {
         getMutableMapField(builder).getMutableList().clear();
       }
 
+      @Override
       public com.google.protobuf.Message.Builder newBuilder() {
         return mapEntryMessageDefaultInstance.newBuilderForType();
       }
 
+      @Override
       public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
         throw new UnsupportedOperationException(
             "Nested builder not supported for map fields.");
       }
 
-      public com.google.protobuf.Message.Builder getRepeatedBuilder(
-          Builder builder, int index) {
+      @Override
+      public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
         throw new UnsupportedOperationException(
             "Nested builder not supported for map fields.");
       }
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 81e1862..df01547 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -30,24 +30,28 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
 import com.google.protobuf.Internal.BooleanList;
 import com.google.protobuf.Internal.DoubleList;
+import com.google.protobuf.Internal.EnumLiteMap;
 import com.google.protobuf.Internal.FloatList;
 import com.google.protobuf.Internal.IntList;
 import com.google.protobuf.Internal.LongList;
 import com.google.protobuf.Internal.ProtobufList;
 import com.google.protobuf.WireFormat.FieldType;
-
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Lite version of {@link GeneratedMessage}.
@@ -56,49 +60,144 @@
  */
 public abstract class GeneratedMessageLite<
     MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
-        extends AbstractMessageLite
-        implements Serializable {
-
-  private static final long serialVersionUID = 1L;
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+        extends AbstractMessageLite<MessageType, BuilderType> {
+  // BEGIN REGULAR
+  static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = false;
+  // END REGULAR
+  // BEGIN EXPERIMENTAL
+  // static final boolean ENABLE_EXPERIMENTAL_RUNTIME_AT_BUILD_TIME = true;
+  // END EXPERIMENTAL
 
   /** For use by generated code only. Lazily initialized to reduce allocations. */
-  protected UnknownFieldSetLite unknownFields = null;
-  
+  protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
+
   /** For use by generated code only.  */
   protected int memoizedSerializedSize = -1;
-  
+
+  @Override
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final Parser<MessageType> getParserForType() {
     return (Parser<MessageType>) dynamicMethod(MethodToInvoke.GET_PARSER);
   }
 
+  @Override
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final MessageType getDefaultInstanceForType() {
     return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE);
   }
 
+  @Override
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final BuilderType newBuilderForType() {
     return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
   }
 
+  /**
+   * A reflective toString function. This is primarily intended as a developer aid, while keeping
+   * binary size down. The first line of the {@code toString()} representation includes a commented
+   * version of {@code super.toString()} to act as an indicator that this should not be relied on
+   * for comparisons.
+   * <p>
+   * NOTE: This method relies on the field getter methods not being stripped or renamed by proguard.
+   * If they are, the fields will not be included in the returned string representation.
+   * <p>
+   * NOTE: This implementation is liable to change in the future, and should not be relied on in
+   * code.
+   */
+  @Override
+  public String toString() {
+    return MessageLiteToString.toString(this, super.toString());
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime
+  @Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    // BEGIN EXPERIMENTAL
+    // memoizedHashCode = Protobuf.getInstance().schemaFor(this).hashCode(this);
+    // return memoizedHashCode;
+    // END EXPERIMENTAL
+    // BEGIN REGULAR
+    HashCodeVisitor visitor = new HashCodeVisitor();
+    visit(visitor, (MessageType) this);
+    memoizedHashCode = visitor.hashCode;
+    return memoizedHashCode;
+    // END REGULAR
+  }
+
+  // BEGIN REGULAR
+  @SuppressWarnings("unchecked") // Guaranteed by runtime
+  int hashCode(HashCodeVisitor visitor) {
+    if (memoizedHashCode == 0) {
+      int inProgressHashCode = visitor.hashCode;
+      visitor.hashCode = 0;
+      visit(visitor, (MessageType) this);
+      memoizedHashCode = visitor.hashCode;
+      visitor.hashCode = inProgressHashCode;
+    }
+    return memoizedHashCode;
+  }
+  // END REGULAR
+
+  @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+  @Override
+  public boolean equals(Object other) {
+    if (this == other) {
+      return true;
+    }
+
+    if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+      return false;
+    }
+
+    // BEGIN EXPERIMENTAL
+    // return Protobuf.getInstance().schemaFor(this).equals(this, (MessageType) other);
+    // END EXPERIMENTAL
+    // BEGIN REGULAR
+
+    try {
+      visit(EqualsVisitor.INSTANCE, (MessageType) other);
+    } catch (EqualsVisitor.NotEqualsException e) {
+      return false;
+    }
+    return true;
+    // END REGULAR
+  }
+
+  // BEGIN REGULAR
+  /** Same as {@link #equals(Object)} but throws {@code NotEqualsException}. */
+  @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+  boolean equals(EqualsVisitor visitor, MessageLite other) {
+    if (this == other) {
+      return true;
+    }
+
+    if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+      return false;
+    }
+
+    visit(visitor, (MessageType) other);
+    return true;
+  }
+  // END REGULAR
+
   // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
   // mutable during the parsing constructor and immutable after. This allows us to avoid
   // any unnecessary intermediary allocations while reducing the generated code size.
 
-  /**
-   * Lazily initializes unknown fields.
-   */
+  /** Lazily initializes unknown fields. */
   private final void ensureUnknownFieldsInitialized() {
-    if (unknownFields == null) {
+    if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
       unknownFields = UnknownFieldSetLite.newInstance();
     }
   }
-  
+
   /**
    * Called by subclasses to parse an unknown field. For use by generated code only.
-   * 
+   *
    * @return {@code true} unless the tag is an end-group tag.
    */
   protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
@@ -106,7 +205,7 @@
     if (WireFormat.getTagWireType(tag) == WireFormat.WIRETYPE_END_GROUP) {
       return false;
     }
-    
+
     ensureUnknownFieldsInitialized();
     return unknownFields.mergeFieldFrom(tag, input);
   }
@@ -118,7 +217,7 @@
     ensureUnknownFieldsInitialized();
     unknownFields.mergeVarintField(tag, value);
   }
-  
+
   /**
    * Called by subclasses to parse an unknown field. For use by generated code only.
    */
@@ -126,22 +225,41 @@
     ensureUnknownFieldsInitialized();
     unknownFields.mergeLengthDelimitedField(fieldNumber, value);
   }
-  
+
   /**
    * Called by subclasses to complete parsing. For use by generated code only.
    */
-  protected void doneParsing() {
-    if (unknownFields == null) {
-      unknownFields = UnknownFieldSetLite.getDefaultInstance();
-    } else {
-      unknownFields.makeImmutable();
-    }
+  protected void makeImmutable() {
+    // BEGIN REGULAR
+    dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+    unknownFields.makeImmutable();
+    // END REGULAR
+    // BEGIN EXPERIMENTAL
+    // Protobuf.getInstance().schemaFor(this).makeImmutable(this);
+    // END EXPERIMENTAL
   }
 
+  protected final <
+    MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+        BuilderType createBuilder() {
+    return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+  }
+
+  protected final <
+    MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+        BuilderType createBuilder(MessageType prototype) {
+    return ((BuilderType) createBuilder()).mergeFrom(prototype);
+  }
+
+  @Override
   public final boolean isInitialized() {
-    return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
+    return isInitialized((MessageType) this, Boolean.TRUE);
   }
 
+  @Override
+  @SuppressWarnings("unchecked")
   public final BuilderType toBuilder() {
     BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
     builder.mergeFrom((MessageType) this);
@@ -155,11 +273,18 @@
    * For use by generated code only.
    */
   public static enum MethodToInvoke {
+    // BEGIN REGULAR
     IS_INITIALIZED,
-    PARSE_PARTIAL_FROM,
-    MERGE_FROM,
+    VISIT,
+    MERGE_FROM_STREAM,
     MAKE_IMMUTABLE,
-    NEW_INSTANCE,
+    // END REGULAR
+    // Rely on/modify instance state
+    GET_MEMOIZED_IS_INITIALIZED,
+    SET_MEMOIZED_IS_INITIALIZED,
+
+    // Rely on static state
+    NEW_MUTABLE_INSTANCE,
     NEW_BUILDER,
     GET_DEFAULT_INSTANCE,
     GET_PARSER;
@@ -170,24 +295,30 @@
    * Theses different kinds of operations are required to implement message-level operations for
    * builders in the runtime. This method bundles those operations to reduce the generated methods
    * count.
+   *
    * <ul>
-   * <li>{@code PARSE_PARTIAL_FROM} is parameterized with an {@link CodedInputStream} and
-   * {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the
-   * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the
-   * implementation wraps it in a RuntimeException
-   * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer
-   * <li>{@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to
-   * memoize. It returns {@code null} for false and the default instance for true. We optionally
-   * memoize to support the Builder case, where memoization is not desired.
-   * <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance.
-   * <li>{@code MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from
-   * that instance into this instance.
-   * <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state.
+   *   <li>{@code MERGE_FROM_STREAM} is parameterized with an {@link CodedInputStream} and {@link
+   *       ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the
+   *       returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException},
+   *       the implementation wraps it in a RuntimeException.
+   *   <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer that has not yet been
+   *       made immutable. See {@code MAKE_IMMUTABLE}.
+   *   <li>{@code IS_INITIALIZED} returns {@code null} for false and the default instance for true.
+   *       It doesn't use or modify any memoized value.
+   *   <li>{@code GET_MEMOIZED_IS_INITIALIZED} returns the memoized {@code isInitialized} byte
+   *       value.
+   *   <li>{@code SET_MEMOIZED_IS_INITIALIZED} sets the memoized {@code isInitilaized} byte value to
+   *       1 if the first parameter is not null, or to 0 if the first parameter is null.
+   *   <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance.
+   *   <li>{@code VISIT} is parameterized with a {@code Visitor} and a {@code MessageType} and
+   *       recursively iterates through the fields side by side between this and the instance.
+   *   <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state.
    * </ul>
+   *
    * This method, plus the implementation of the Builder, enables the Builder class to be proguarded
    * away entirely on Android.
-   * <p>
-   * For use by generated code only.
+   *
+   * <p>For use by generated code only.
    */
   protected abstract Object dynamicMethod(MethodToInvoke method, Object arg0, Object arg1);
 
@@ -205,9 +336,27 @@
     return dynamicMethod(method, null, null);
   }
 
+  // BEGIN REGULAR
+  void visit(Visitor visitor, MessageType other) {
+    dynamicMethod(MethodToInvoke.VISIT, visitor, other);
+    unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
+  }
+  // END REGULAR
+
+  @Override
+  int getMemoizedSerializedSize() {
+    return memoizedSerializedSize;
+  }
+
+  @Override
+  void setMemoizedSerializedSize(int size) {
+    memoizedSerializedSize = size;
+  }
+
+
+
   /**
-   * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
-   * message.
+   * Merge some unknown fields into the {@link UnknownFieldSetLite} for this message.
    *
    * <p>For use by generated code only.
    */
@@ -219,7 +368,7 @@
   public abstract static class Builder<
       MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
       BuilderType extends Builder<MessageType, BuilderType>>
-          extends AbstractMessageLite.Builder<BuilderType> {
+          extends AbstractMessageLite.Builder<MessageType, BuilderType> {
 
     private final MessageType defaultInstance;
     protected MessageType instance;
@@ -227,7 +376,8 @@
 
     protected Builder(MessageType defaultInstance) {
       this.defaultInstance = defaultInstance;
-      this.instance = (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+      this.instance =
+          (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
       isBuilt = false;
     }
 
@@ -237,26 +387,27 @@
      */
     protected void copyOnWrite() {
       if (isBuilt) {
-        MessageType newInstance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
-        newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance);
+        MessageType newInstance =
+            (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+        mergeFromInstance(newInstance, instance);
         instance = newInstance;
         isBuilt = false;
       }
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final boolean isInitialized() {
       return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */);
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final BuilderType clear() {
       // No need to copy on write since we're dropping the instance anyways.
-      instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+      instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
       return (BuilderType) this;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public BuilderType clone() {
       BuilderType builder =
           (BuilderType) getDefaultInstanceForType().newBuilderForType();
@@ -264,20 +415,19 @@
       return builder;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public MessageType buildPartial() {
       if (isBuilt) {
         return instance;
       }
-      
-      instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
-      instance.unknownFields.makeImmutable();
-      
+
+      instance.makeImmutable();
+
       isBuilt = true;
       return instance;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final MessageType build() {
       MessageType result = buildPartial();
       if (!result.isInitialized()) {
@@ -285,34 +435,74 @@
       }
       return result;
     }
-    
+
+    @Override
+    protected BuilderType internalMergeFrom(MessageType message) {
+      return mergeFrom(message);
+    }
+
     /** All subclasses implement this. */
     public BuilderType mergeFrom(MessageType message) {
       copyOnWrite();
-      instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message);
+      mergeFromInstance(instance, message);
       return (BuilderType) this;
     }
-    
+
+    private void mergeFromInstance(MessageType dest, MessageType src) {
+      // BEGIN EXPERIMENTAL
+      // Protobuf.getInstance().schemaFor(dest).mergeFrom(dest, src);
+      // END EXPERIMENTAL
+      // BEGIN REGULAR
+      dest.visit(MergeFromVisitor.INSTANCE, src);
+      // END REGULAR
+    }
+
+    @Override
     public MessageType getDefaultInstanceForType() {
       return defaultInstance;
     }
-    
+
+    @Override
+    public BuilderType mergeFrom(byte[] input, int offset, int length)
+        throws InvalidProtocolBufferException {
+      // BEGIN REGULAR
+      return super.mergeFrom(input, offset, length);
+      // END REGULAR
+      // BEGIN EXPERIMENTAL
+      // copyOnWrite();
+      // try {
+      //   Protobuf.getInstance().schemaFor(instance).mergeFrom(
+      //       instance, input, offset, offset + length, new ArrayDecoders.Registers());
+      // } catch (InvalidProtocolBufferException e) {
+      //   throw e;
+      // } catch (IndexOutOfBoundsException e) {
+      //   throw InvalidProtocolBufferException.truncatedMessage();
+      // } catch (IOException e) {
+      //   throw new RuntimeException("Reading from byte array should not throw IOException.", e);
+      // }
+      // return (BuilderType) this;
+      // END EXPERIMENTAL
+    }
+
+    @Override
     public BuilderType mergeFrom(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      MessageType parsedMessage = null;
+        throws IOException {
+      copyOnWrite();
       try {
-        parsedMessage =
-            (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom(
-                input, extensionRegistry);
-      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-        parsedMessage = (MessageType) e.getUnfinishedMessage();
-        throw e;
-      } finally {
-        if (parsedMessage != null) {
-          mergeFrom(parsedMessage);
+        // BEGIN REGULAR
+        instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+        // END REGULAR
+        // BEGIN EXPERIMENTAL
+        // Protobuf.getInstance().schemaFor(instance).mergeFrom(
+        //     instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
+        // END EXPERIMENTAL
+      } catch (RuntimeException e) {
+        if (e.getCause() instanceof IOException) {
+          throw (IOException) e.getCause();
         }
+        throw e;
       }
       return (BuilderType) this;
     }
@@ -356,32 +546,38 @@
             extends GeneratedMessageLite<MessageType, BuilderType>
             implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
 
-    /**
-     * Represents the set of extensions on this message. For use by generated
-     * code only.
-     */
-    protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
+    /** Represents the set of extensions on this message. For use by generated code only. */
+    protected FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
 
+    @SuppressWarnings("unchecked")
     protected final void mergeExtensionFields(final MessageType other) {
       if (extensions.isImmutable()) {
         extensions = extensions.clone();
       }
       extensions.mergeFrom(((ExtendableMessage) other).extensions);
     }
-    
+
+    // BEGIN REGULAR
+    @Override
+    final void visit(Visitor visitor, MessageType other) {
+      super.visit(visitor, other);
+      extensions = visitor.visitExtensions(extensions, other.extensions);
+    }
+    // END REGULAR
+
     /**
      * Parse an unknown field or an extension. For use by generated code only.
-     * 
+     *
      * <p>For use by generated code only.
-     * 
+     *
      * @return {@code true} unless the tag is an end-group tag.
      */
     protected <MessageType extends MessageLite> boolean parseUnknownField(
         MessageType defaultInstance,
         CodedInputStream input,
         ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      int wireType = WireFormat.getTagWireType(tag);
+        int tag)
+        throws IOException {
       int fieldNumber = WireFormat.getTagFieldNumber(tag);
 
       // TODO(dweis): How much bytecode would be saved by not requiring the generated code to
@@ -389,6 +585,17 @@
       GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(
           defaultInstance, fieldNumber);
 
+      return parseExtension(input, extensionRegistry, extension, tag, fieldNumber);
+    }
+
+    private boolean parseExtension(
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        GeneratedExtension<?, ?> extension,
+        int tag,
+        int fieldNumber)
+        throws IOException {
+      int wireType = WireFormat.getTagWireType(tag);
       boolean unknown = false;
       boolean packed = false;
       if (extension == null) {
@@ -411,6 +618,8 @@
         return parseUnknownField(tag, input);
       }
 
+      ensureExtensionsAreMutable();
+
       if (packed) {
         int length = input.readRawVarint32();
         int limit = input.pushLimit(length);
@@ -489,10 +698,156 @@
                               extension.singularToFieldSetType(value));
         }
       }
-
       return true;
     }
     
+    /**
+     * Parse an unknown field or an extension. For use by generated code only.
+     *
+     * <p>For use by generated code only.
+     *
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected <MessageType extends MessageLite> boolean parseUnknownFieldAsMessageSet(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        int tag)
+        throws IOException {
+
+      if (tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+        mergeMessageSetExtensionFromCodedStream(defaultInstance, input, extensionRegistry);
+        return true;
+      }
+
+      // TODO(dweis): Do we really want to support non message set wire format in message sets?
+      // Full runtime does... So we do for now.
+      int wireType = WireFormat.getTagWireType(tag);
+      if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
+        return parseUnknownField(defaultInstance, input, extensionRegistry, tag);
+      } else {
+        // TODO(dweis): Should we throw on invalid input? Full runtime does not...
+        return input.skipField(tag);
+      }
+    }
+
+    /**
+     * Merges the message set from the input stream; requires message set wire format.
+     * 
+     * @param defaultInstance the default instance of the containing message we are parsing in
+     * @param input the stream to parse from
+     * @param extensionRegistry the registry to use when parsing
+     */
+    private <MessageType extends MessageLite> void mergeMessageSetExtensionFromCodedStream(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      // The wire format for MessageSet is:
+      //   message MessageSet {
+      //     repeated group Item = 1 {
+      //       required int32 typeId = 2;
+      //       required bytes message = 3;
+      //     }
+      //   }
+      // "typeId" is the extension's field number.  The extension can only be
+      // a message type, where "message" contains the encoded bytes of that
+      // message.
+      //
+      // In practice, we will probably never see a MessageSet item in which
+      // the message appears before the type ID, or where either field does not
+      // appear exactly once.  However, in theory such cases are valid, so we
+      // should be prepared to accept them.
+
+      int typeId = 0;
+      ByteString rawBytes = null; // If we encounter "message" before "typeId"
+      GeneratedExtension<?, ?> extension = null;
+
+      // Read bytes from input, if we get it's type first then parse it eagerly,
+      // otherwise we store the raw bytes in a local variable.
+      while (true) {
+        final int tag = input.readTag();
+        if (tag == 0) {
+          break;
+        }
+
+        if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+          typeId = input.readUInt32();
+          if (typeId != 0) {
+            extension = extensionRegistry.findLiteExtensionByNumber(defaultInstance, typeId);
+          }
+
+        } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+          if (typeId != 0) {
+            if (extension != null) {
+              // We already know the type, so we can parse directly from the
+              // input with no copying.  Hooray!
+              eagerlyMergeMessageSetExtension(input, extension, extensionRegistry, typeId);
+              rawBytes = null;
+              continue;
+            }
+          }
+          // We haven't seen a type ID yet or we want parse message lazily.
+          rawBytes = input.readBytes();
+
+        } else { // Unknown tag. Skip it.
+          if (!input.skipField(tag)) {
+            break; // End of group
+          }
+        }
+      }
+      input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+      // Process the raw bytes.
+      if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
+        if (extension != null) { // We known the type
+          mergeMessageSetExtensionFromBytes(rawBytes, extensionRegistry, extension);
+        } else { // We don't know how to parse this. Ignore it.
+          if (rawBytes != null) {
+            mergeLengthDelimitedField(typeId, rawBytes);
+          }
+        }
+      }
+    }
+
+    private void eagerlyMergeMessageSetExtension(
+        CodedInputStream input,
+        GeneratedExtension<?, ?> extension,
+        ExtensionRegistryLite extensionRegistry,
+        int typeId)
+        throws IOException {
+      int fieldNumber = typeId;
+      int tag = WireFormat.makeTag(typeId, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      parseExtension(input, extensionRegistry, extension, tag, fieldNumber);
+    }
+
+    private void mergeMessageSetExtensionFromBytes(
+        ByteString rawBytes,
+        ExtensionRegistryLite extensionRegistry,
+        GeneratedExtension<?, ?> extension)
+        throws IOException {
+      MessageLite.Builder subBuilder = null;
+      MessageLite existingValue = (MessageLite) extensions.getField(extension.descriptor);
+      if (existingValue != null) {
+        subBuilder = existingValue.toBuilder();
+      }
+      if (subBuilder == null) {
+        subBuilder = extension.getMessageDefaultInstance().newBuilderForType();
+      }
+      subBuilder.mergeFrom(rawBytes, extensionRegistry);
+      MessageLite value = subBuilder.build();
+
+      ensureExtensionsAreMutable().setField(
+          extension.descriptor, extension.singularToFieldSetType(value));
+    }
+
+    private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+      return extensions;
+    }
+
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
       if (extension.getContainingTypeDefaultInstance() !=
@@ -505,35 +860,33 @@
     }
 
     /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final ExtensionLite<MessageType, Type> extension) {
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       return extensions.hasField(extensionLite.descriptor);
     }
 
     /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final <Type> int getExtensionCount(
         final ExtensionLite<MessageType, List<Type>> extension) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       return extensions.getRepeatedFieldCount(extensionLite.descriptor);
     }
 
     /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, Type> extension) {
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       final Object value = extensions.getField(extensionLite.descriptor);
       if (value == null) {
@@ -544,11 +897,10 @@
     }
 
     /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, List<Type>> extension,
-        final int index) {
+        final ExtensionLite<MessageType, List<Type>> extension, final int index) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
 
@@ -562,14 +914,15 @@
       return extensions.isInitialized();
     }
 
-
     @Override
-    protected final void doneParsing() {
-      super.doneParsing();
-      
+    protected final void makeImmutable() {
+      super.makeImmutable();
+      // BEGIN REGULAR
       extensions.makeImmutable();
+      // END REGULAR
     }
 
+
     /**
      * Used by subclasses to serialize extensions.  Extension ranges may be
      * interleaved with field numbers, but we must write them in canonical
@@ -640,12 +993,6 @@
       implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
     protected ExtendableBuilder(MessageType defaultInstance) {
       super(defaultInstance);
-      
-      // TODO(dweis): This is kind of an unnecessary clone since we construct a
-      //     new instance in the parent constructor which makes the extensions
-      //     immutable. This extra allocation shouldn't matter in practice
-      //     though.
-      instance.extensions = instance.extensions.clone();
     }
 
     // For immutable message conversion.
@@ -654,17 +1001,26 @@
       instance.extensions = extensions;
     }
 
-    // @Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     protected void copyOnWrite() {
       if (!isBuilt) {
         return;
       }
-      
+
       super.copyOnWrite();
       instance.extensions = instance.extensions.clone();
     }
 
-    // @Override (Java 1.6 override semantics, but we must support 1.5)
+    private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+      FieldSet<ExtensionDescriptor> extensions = instance.extensions;
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+        instance.extensions = extensions;
+      }
+      return extensions;
+    }
+
+    @Override
     public final MessageType buildPartial() {
       if (isBuilt) {
         return instance;
@@ -686,54 +1042,44 @@
     }
 
     /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final ExtensionLite<MessageType, Type> extension) {
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
       return instance.hasExtension(extension);
     }
 
     /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public final <Type> int getExtensionCount(
         final ExtensionLite<MessageType, List<Type>> extension) {
       return instance.getExtensionCount(extension);
     }
 
     /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, Type> extension) {
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
       return instance.getExtension(extension);
     }
 
     /** Get one element of a repeated extension. */
+    @Override
     @SuppressWarnings("unchecked")
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> Type getExtension(
-        final ExtensionLite<MessageType, List<Type>> extension,
-        final int index) {
+        final ExtensionLite<MessageType, List<Type>> extension, final int index) {
       return instance.getExtension(extension, index);
     }
 
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      return super.clone();
-    }
-    
     /** Set the value of an extension. */
     public final <Type> BuilderType setExtension(
         final ExtensionLite<MessageType, Type> extension,
         final Type value) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
-      instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -743,11 +1089,12 @@
         final int index, final Type value) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
-      instance.extensions.setRepeatedField(
-          extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .setRepeatedField(
+              extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -757,11 +1104,11 @@
         final Type value) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
-      instance.extensions.addRepeatedField(
-          extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .addRepeatedField(extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -769,10 +1116,10 @@
     public final <Type> BuilderType clearExtension(
         final ExtensionLite<MessageType, ?> extension) {
       GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
-      instance.extensions.clearField(extensionLite.descriptor);
+      ensureExtensionsAreMutable().clearField(extensionLite.descriptor);
       return (BuilderType) this;
     }
   }
@@ -844,37 +1191,44 @@
     final boolean isRepeated;
     final boolean isPacked;
 
+    @Override
     public int getNumber() {
       return number;
     }
 
+    @Override
     public WireFormat.FieldType getLiteType() {
       return type;
     }
 
+    @Override
     public WireFormat.JavaType getLiteJavaType() {
       return type.getJavaType();
     }
 
+    @Override
     public boolean isRepeated() {
       return isRepeated;
     }
 
+    @Override
     public boolean isPacked() {
       return isPacked;
     }
 
+    @Override
     public Internal.EnumLiteMap<?> getEnumType() {
       return enumTypeMap;
     }
 
+    @Override
     @SuppressWarnings("unchecked")
-    public MessageLite.Builder internalMergeFrom(
-        MessageLite.Builder to, MessageLite from) {
+    public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
       return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
     }
 
 
+    @Override
     public int compareTo(ExtensionDescriptor other) {
       return number - other.number;
     }
@@ -915,6 +1269,7 @@
     }
   }
 
+
   /**
    * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
    *
@@ -969,6 +1324,7 @@
     }
 
     /** Get the field number. */
+    @Override
     public int getNumber() {
       return descriptor.getNumber();
     }
@@ -978,6 +1334,7 @@
      * If the extension is an embedded message or group, returns the default
      * instance of the message.
      */
+    @Override
     public MessageLite getMessageDefaultInstance() {
       return messageDefaultInstance;
     }
@@ -1032,14 +1389,17 @@
       }
     }
 
+    @Override
     public FieldType getLiteType() {
       return descriptor.getLiteType();
     }
 
+    @Override
     public boolean isRepeated() {
       return descriptor.isRepeated;
     }
 
+    @Override
     public Type getDefaultValue() {
       return defaultValue;
     }
@@ -1049,7 +1409,12 @@
    * A serialized (serializable) form of the generated message.  Stores the
    * message as a class name and a byte array.
    */
-  static final class SerializedForm implements Serializable {
+  protected static final class SerializedForm implements Serializable {
+
+    public static SerializedForm of(MessageLite message) {
+      return new SerializedForm(message);
+    }
+
     private static final long serialVersionUID = 0L;
 
     private final String messageClassName;
@@ -1083,7 +1448,7 @@
       } catch (ClassNotFoundException e) {
         throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
       } catch (NoSuchFieldException e) {
-        throw new RuntimeException("Unable to find DEFAULT_INSTANCE in " + messageClassName, e);
+        return readResolveFallback();
       } catch (SecurityException e) {
         throw new RuntimeException("Unable to call DEFAULT_INSTANCE in " + messageClassName, e);
       } catch (IllegalAccessException e) {
@@ -1092,19 +1457,36 @@
         throw new RuntimeException("Unable to understand proto buffer", e);
       }
     }
+
+    /**
+     * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 generated code.
+     */
+    @Deprecated
+    private Object readResolveFallback() throws ObjectStreamException {
+      try {
+        Class<?> messageClass = Class.forName(messageClassName);
+        java.lang.reflect.Field defaultInstanceField =
+            messageClass.getDeclaredField("defaultInstance");
+        defaultInstanceField.setAccessible(true);
+        MessageLite defaultInstance = (MessageLite) defaultInstanceField.get(null);
+        return defaultInstance.newBuilderForType()
+            .mergeFrom(asBytes)
+            .buildPartial();
+      } catch (ClassNotFoundException e) {
+        throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
+      } catch (NoSuchFieldException e) {
+        throw new RuntimeException("Unable to find defaultInstance in " + messageClassName, e);
+      } catch (SecurityException e) {
+        throw new RuntimeException("Unable to call defaultInstance in " + messageClassName, e);
+      } catch (IllegalAccessException e) {
+        throw new RuntimeException("Unable to call parsePartialFrom", e);
+      } catch (InvalidProtocolBufferException e) {
+        throw new RuntimeException("Unable to understand proto buffer", e);
+      }
+    }
   }
 
   /**
-   * Replaces this object in the output stream with a serialized form.
-   * Part of Java's serialization magic.  Generated sub-classes must override
-   * this method by calling {@code return super.writeReplace();}
-   * @return a SerializedForm of this message
-   */
-  protected Object writeReplace() throws ObjectStreamException {
-    return new SerializedForm(this);
-  }
-  
-  /**
    * Checks that the {@link Extension} is Lite and returns it as a
    * {@link GeneratedExtension}.
    */
@@ -1117,7 +1499,7 @@
     if (!extension.isLite()) {
       throw new IllegalArgumentException("Expected a lite extension.");
     }
-    
+
     return (GeneratedExtension<MessageType, T>) extension;
   }
 
@@ -1128,31 +1510,88 @@
    */
   protected static final <T extends GeneratedMessageLite<T, ?>> boolean isInitialized(
       T message, boolean shouldMemoize) {
-    return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null;
-  }
-  
-  protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
-    message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
-  }
-  
-  /**
-   * A static helper method for parsing a partial from input using the extension registry and the
-   * instance.
-   */
-  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
-      T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-          throws InvalidProtocolBufferException {
-    try {
-      return (T) instance.dynamicMethod(
-          MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry);
-    } catch (RuntimeException e) {
-      if (e.getCause() instanceof InvalidProtocolBufferException) {
-        throw (InvalidProtocolBufferException) e.getCause();
-      }
-      throw e;
+    byte memoizedIsInitialized =
+        (Byte) message.dynamicMethod(MethodToInvoke.GET_MEMOIZED_IS_INITIALIZED);
+    if (memoizedIsInitialized == 1) {
+      return true;
     }
+    if (memoizedIsInitialized == 0) {
+      return false;
+    }
+    // BEGIN EXPERIMENTAL
+    // boolean isInitialized = Protobuf.getInstance().schemaFor(message).isInitialized(message);
+    // END EXPERIMENTAL
+    // BEGIN REGULAR
+    boolean isInitialized =
+        message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.FALSE) != null;
+    // END REGULAR
+    if (shouldMemoize) {
+      message.dynamicMethod(
+          MethodToInvoke.SET_MEMOIZED_IS_INITIALIZED, isInitialized ? message : null);
+    }
+    return isInitialized;
   }
-  
+
+  protected static IntList emptyIntList() {
+    return IntArrayList.emptyList();
+  }
+
+  protected static IntList mutableCopy(IntList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static LongList emptyLongList() {
+    return LongArrayList.emptyList();
+  }
+
+  protected static LongList mutableCopy(LongList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static FloatList emptyFloatList() {
+    return FloatArrayList.emptyList();
+  }
+
+  protected static FloatList mutableCopy(FloatList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static DoubleList emptyDoubleList() {
+    return DoubleArrayList.emptyList();
+  }
+
+  protected static DoubleList mutableCopy(DoubleList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static BooleanList emptyBooleanList() {
+    return BooleanArrayList.emptyList();
+  }
+
+  protected static BooleanList mutableCopy(BooleanList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static <E> ProtobufList<E> emptyProtobufList() {
+    return ProtobufArrayList.emptyList();
+  }
+
+  protected static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
   /**
    * A {@link Parser} implementation that delegates to the default instance.
    * <p>
@@ -1160,117 +1599,954 @@
    */
   protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
       extends AbstractParser<T> {
-    
+
     private T defaultInstance;
-    
+
     public DefaultInstanceBasedParser(T defaultInstance) {
       this.defaultInstance = defaultInstance;
     }
-    
+
     @Override
     public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
     }
-  }
-  
-  protected static IntList newIntList() {
-    return new IntArrayList();
-  }
-  
-  protected static IntList newIntListWithCapacity(int capacity) {
-    return new IntArrayList(capacity);
-  }
-  
-  protected static IntList newIntList(List<Integer> toCopy) {
-    return new IntArrayList(toCopy);
-  }
-  
-  protected static IntList emptyIntList() {
-    return IntArrayList.emptyList();
+
+    @Override
+    public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException {
+      return GeneratedMessageLite.parsePartialFrom(defaultInstance, input);
+    }
   }
 
-  protected static LongList newLongList() {
-    return new LongArrayList();
+  /**
+   * A static helper method for parsing a partial from input using the extension registry and the
+   * instance.
+   */
+  // TODO(dweis): Should this verify that the last tag was 0?
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+    @SuppressWarnings("unchecked") // Guaranteed by protoc
+    T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+    try {
+      // BEGIN REGULAR
+      result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+      // END REGULAR
+      // BEGIN EXPERIMENTAL
+      // Protobuf.getInstance().schemaFor(result).mergeFrom(
+      //     result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
+      // END EXPERIMENTAL
+      result.makeImmutable();
+      // BEGIN EXPERIMENTAL
+      // } catch (IOException e) {
+      //   if (e.getCause() instanceof InvalidProtocolBufferException) {
+      //     throw (InvalidProtocolBufferException) e.getCause();
+      //   }
+      //   throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
+      // END EXPERIMENTAL
+    } catch (RuntimeException e) {
+      if (e.getCause() instanceof InvalidProtocolBufferException) {
+        throw (InvalidProtocolBufferException) e.getCause();
+      }
+      throw e;
+    }
+    return result;
   }
 
-  protected static LongList newLongListWithCapacity(int capacity) {
-    return new LongArrayList(capacity);
+  /** A static helper method for parsing a partial from byte array. */
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input)
+      throws InvalidProtocolBufferException {
+    // BEGIN REGULAR
+    return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry());
+    // END REGULAR
+    // BEGIN EXPERIMENTAL
+    // @SuppressWarnings("unchecked") // Guaranteed by protoc
+    // T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+    // try {
+    //   Protobuf.getInstance().schemaFor(result).mergeFrom(
+    //       result, input, 0, input.length, new ArrayDecoders.Registers());
+    //   result.makeImmutable();
+    //   if (result.memoizedHashCode != 0) {
+    //     throw new RuntimeException();
+    //   }
+    // } catch (IOException e) {
+    //   if (e.getCause() instanceof InvalidProtocolBufferException) {
+    //     throw (InvalidProtocolBufferException) e.getCause();
+    //   }
+    //   throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
+    // } catch (IndexOutOfBoundsException e) {
+    //   throw InvalidProtocolBufferException.truncatedMessage().setUnfinishedMessage(result);
+    // }
+    // return result;
+    // END EXPERIMENTAL
   }
-  
-  protected static LongList newLongList(List<Long> toCopy) {
-    return new LongArrayList(toCopy);
+
+  protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance,
+      CodedInputStream input)
+      throws InvalidProtocolBufferException {
+    return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
   }
-  
-  protected static LongList emptyLongList() {
-    return LongArrayList.emptyList();
+
+  /**
+   * Helper method to check if message is initialized.
+   *
+   * @throws InvalidProtocolBufferException if it is not initialized.
+   * @return The message to check.
+   */
+  private static <T extends GeneratedMessageLite<T, ?>> T checkMessageInitialized(T message)
+      throws InvalidProtocolBufferException {
+    if (message != null && !message.isInitialized()) {
+      throw message.newUninitializedMessageException()
+          .asInvalidProtocolBufferException()
+          .setUnfinishedMessage(message);
+    }
+    return message;
   }
-  
-  protected static FloatList newFloatList() {
-    return new FloatArrayList();
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parseFrom(defaultInstance, CodedInputStream.newInstance(data), extensionRegistry));
   }
-  
-  protected static FloatList newFloatListWithCapacity(int capacity) {
-    return new FloatArrayList(capacity);
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteBuffer data) throws InvalidProtocolBufferException {
+    return parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry());
   }
-  
-  protected static FloatList newFloatList(List<Float> toCopy) {
-    return new FloatArrayList(toCopy);
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteString data)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
   }
-  
-  protected static FloatList emptyFloatList() {
-    return FloatArrayList.emptyList();
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
   }
-  
-  protected static DoubleList newDoubleList() {
-    return new DoubleArrayList();
+
+  // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+  // ByteString.
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    T message;
+    try {
+      CodedInputStream input = data.newCodedInput();
+      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
   }
-  
-  protected static DoubleList newDoubleListWithCapacity(int capacity) {
-    return new DoubleArrayList(capacity);
+
+  // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+  // ByteString.
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    T message;
+    try {
+      CodedInputStream input = CodedInputStream.newInstance(data);
+      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
   }
-  
-  protected static DoubleList newDoubleList(List<Double> toCopy) {
-    return new DoubleArrayList(toCopy);
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, byte[] data)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(defaultInstance, data));
   }
-  
-  protected static DoubleList emptyDoubleList() {
-    return DoubleArrayList.emptyList();
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
   }
-  
-  protected static BooleanList newBooleanList() {
-    return new BooleanArrayList();
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, InputStream input)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input),
+            ExtensionRegistryLite.getEmptyRegistry()));
   }
-  
-  protected static BooleanList newBooleanListWithCapacity(int capacity) {
-    return new BooleanArrayList(capacity);
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input), extensionRegistry));
   }
-  
-  protected static BooleanList newBooleanList(List<Boolean> toCopy) {
-    return new BooleanArrayList(toCopy);
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, CodedInputStream input)
+      throws InvalidProtocolBufferException {
+    return parseFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
   }
-  
-  protected static BooleanList emptyBooleanList() {
-    return BooleanArrayList.emptyList();
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, input, extensionRegistry));
   }
-  
-  protected static <E> ProtobufList<E> newProtobufList() {
-    return new ProtobufArrayList<E>();
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+      T defaultInstance, InputStream input)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialDelimitedFrom(defaultInstance, input,
+            ExtensionRegistryLite.getEmptyRegistry()));
   }
-  
-  protected static <E> ProtobufList<E> newProtobufList(List<E> toCopy) {
-    return new ProtobufArrayList<E>(toCopy);
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+      T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry));
   }
-  
-  protected static <E> ProtobufList<E> newProtobufListWithCapacity(int capacity) {
-    return new ProtobufArrayList<E>(capacity);
+
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialDelimitedFrom(
+      T defaultInstance,
+      InputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    int size;
+    try {
+      int firstByte = input.read();
+      if (firstByte == -1) {
+        return null;
+      }
+      size = CodedInputStream.readRawVarint32(firstByte, input);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e.getMessage());
+    }
+    InputStream limitedInput = new LimitedInputStream(input, size);
+    CodedInputStream codedInput = CodedInputStream.newInstance(limitedInput);
+    T message = parsePartialFrom(defaultInstance, codedInput, extensionRegistry);
+    try {
+      codedInput.checkLastTagWas(0);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(message);
+    }
+    return message;
   }
-  
-  protected static <E> ProtobufList<E> emptyProtobufList() {
-    return ProtobufArrayList.emptyList();
+
+  // BEGIN REGULAR
+  /**
+   * An abstract visitor that the generated code calls into that we use to implement various
+   * features. Fields that are not members of oneofs are always visited. Members of a oneof are only
+   * visited when they are the set oneof case value on the "other" proto. The visitOneofNotSet
+   * method is invoked if other's oneof case is not set.
+   */
+  protected interface Visitor {
+    boolean visitBoolean(boolean minePresent, boolean mine, boolean otherPresent, boolean other);
+    int visitInt(boolean minePresent, int mine, boolean otherPresent, int other);
+    double visitDouble(boolean minePresent, double mine, boolean otherPresent, double other);
+    float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other);
+    long visitLong(boolean minePresent, long mine, boolean otherPresent, long other);
+    String visitString(boolean minePresent, String mine, boolean otherPresent, String other);
+    ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other);
+
+    Object visitOneofBoolean(boolean minePresent, Object mine, Object other);
+    Object visitOneofInt(boolean minePresent, Object mine, Object other);
+    Object visitOneofDouble(boolean minePresent, Object mine, Object other);
+    Object visitOneofFloat(boolean minePresent, Object mine, Object other);
+    Object visitOneofLong(boolean minePresent, Object mine, Object other);
+    Object visitOneofString(boolean minePresent, Object mine, Object other);
+    Object visitOneofByteString(boolean minePresent, Object mine, Object other);
+    Object visitOneofMessage(boolean minePresent, Object mine, Object other);
+    void visitOneofNotSet(boolean minePresent);
+
+    /**
+     * Message fields use null sentinals.
+     */
+    <T extends MessageLite> T visitMessage(T mine, T other);
+
+    <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
+    BooleanList visitBooleanList(BooleanList mine, BooleanList other);
+    IntList visitIntList(IntList mine, IntList other);
+    DoubleList visitDoubleList(DoubleList mine, DoubleList other);
+    FloatList visitFloatList(FloatList mine, FloatList other);
+    LongList visitLongList(LongList mine, LongList other);
+    FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other);
+    UnknownFieldSetLite visitUnknownFields(UnknownFieldSetLite mine, UnknownFieldSetLite other);
+    <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other);
   }
-  
-  protected static LazyStringArrayList emptyLazyStringArrayList() {
-    return LazyStringArrayList.emptyList();
+
+  /**
+   * Implements equals. Throws a {@link NotEqualsException} when not equal.
+   */
+  static class EqualsVisitor implements Visitor {
+
+    static final class NotEqualsException extends RuntimeException {}
+
+    static final EqualsVisitor INSTANCE = new EqualsVisitor();
+
+    static final NotEqualsException NOT_EQUALS = new NotEqualsException();
+
+    private EqualsVisitor() {}
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      if (minePresent != otherPresent || !mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      if (minePresent != otherPresent || !mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      if (minePresent) {
+        throw NOT_EQUALS;
+      }
+    }
+
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      if (mine == null && other == null) {
+        return null;
+      }
+
+      if (mine == null || other == null) {
+        throw NOT_EQUALS;
+      }
+
+      ((GeneratedMessageLite<?, ?>) mine).equals(this, other);
+
+      return mine;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
   }
+
+  /**
+   * Implements hashCode by accumulating state.
+   */
+  static class HashCodeVisitor implements Visitor {
+
+    // The caller must ensure that the visitor is invoked parameterized with this and this such that
+    // other is this. This is required due to how oneof cases are handled. See the class comment
+    // on Visitor for more information.
+
+    int hashCode = 0;
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      hashCode = (53 * hashCode) + Internal.hashBoolean(mine);
+      return mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      hashCode = (53 * hashCode) + mine;
+      return mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits(mine));
+      return mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      hashCode = (53 * hashCode) + Float.floatToIntBits(mine);
+      return mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(mine);
+      return mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashBoolean(((Boolean) mine));
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + (Integer) mine;
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits((Double) mine));
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Float.floatToIntBits((Float) mine);
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashLong((Long) mine);
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      return visitMessage((MessageLite) mine, (MessageLite) other);
+    }
+
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      if (minePresent) {
+        throw new IllegalStateException(); // Can't happen if other == this.
+      }
+    }
+
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      final int protoHash;
+      if (mine != null) {
+        if (mine instanceof GeneratedMessageLite) {
+          protoHash = ((GeneratedMessageLite) mine).hashCode(this);
+        } else {
+          protoHash = mine.hashCode();
+        }
+      } else {
+        protoHash = 37;
+      }
+      hashCode = (53 * hashCode) + protoHash;
+      return mine;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+  }
+
+  /**
+   * Implements field merging semantics over the visitor interface.
+   */
+  protected static class MergeFromVisitor implements Visitor {
+
+    public static final MergeFromVisitor INSTANCE = new MergeFromVisitor();
+
+    private MergeFromVisitor() {}
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent) {
+        return visitMessage((MessageLite) mine, (MessageLite) other);
+      }
+      return other;
+    }
+
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      return;
+    }
+
+    @SuppressWarnings("unchecked") // Guaranteed by runtime.
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      if (mine != null && other != null) {
+        return (T) mine.toBuilder().mergeFrom(other).build();
+      }
+
+      return mine != null ? mine : other;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      if (mine.isImmutable()) {
+        mine = mine.clone();
+      }
+      mine.mergeFrom(other);
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      return other == UnknownFieldSetLite.getDefaultInstance()
+          ? mine : UnknownFieldSetLite.mutableCopyOf(mine, other);
+    }
+
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      if (!other.isEmpty()) {
+        if (!mine.isMutable()) {
+          mine = mine.mutableCopy();
+        }
+        mine.mergeFrom(other);
+      }
+      return mine;
+    }
+  }
+  // END REGULAR
 }
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
new file mode 100644
index 0000000..4acd8f2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -0,0 +1,2861 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.Internal.checkNotNull;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+// In opensource protobuf, we have versioned this GeneratedMessageV3 class to GeneratedMessageV3V3 and
+// in the future may have GeneratedMessageV3V4 etc. This allows us to change some aspects of this
+// class without breaking binary compatibility with old generated code that still subclasses
+// the old GeneratedMessageV3 class. To allow these different GeneratedMessageV3V? classes to
+// interoperate (e.g., a GeneratedMessageV3V3 object has a message extension field whose class
+// type is GeneratedMessageV3V4), these classes still share a common parent class AbstractMessage
+// and are using the same GeneratedMessage.GeneratedExtension class for extension definitions.
+// Since this class becomes GeneratedMessageV3V? in opensource, we have to add an import here
+// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
+// this file is also excluded from opensource to avoid conflict.
+import com.google.protobuf.GeneratedMessage.GeneratedExtension;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * All generated protocol message classes extend this class.  This class
+ * implements most of the Message and Builder interfaces using Java reflection.
+ * Users can ignore this class and pretend that generated messages implement
+ * the Message interface directly.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessageV3 extends AbstractMessage
+    implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * For testing. Allows a test to disable the optimization that avoids using
+   * field builders for nested messages until they are requested. By disabling
+   * this optimization, existing tests can be reused to test the field builders.
+   */
+  protected static boolean alwaysUseFieldBuilders = false;
+
+  /** For use by generated code only.  */
+  protected UnknownFieldSet unknownFields;
+
+  protected GeneratedMessageV3() {
+    unknownFields = UnknownFieldSet.getDefaultInstance();
+  }
+
+  protected GeneratedMessageV3(Builder<?> builder) {
+    unknownFields = builder.getUnknownFields();
+  }
+
+  @Override
+  public Parser<? extends GeneratedMessageV3> getParserForType() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+ /**
+  * For testing. Allows a test to disable the optimization that avoids using
+  * field builders for nested messages until they are requested. By disabling
+  * this optimization, existing tests can be reused to test the field builders.
+  * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
+  */
+  static void enableAlwaysUseFieldBuildersForTesting() {
+    alwaysUseFieldBuilders = true;
+  }
+
+  /**
+   * Get the FieldAccessorTable for this type.  We can't have the message
+   * class pass this in to the constructor because of bootstrapping trouble
+   * with DescriptorProtos.
+   */
+  protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+  @Override
+  public Descriptor getDescriptorForType() {
+    return internalGetFieldAccessorTable().descriptor;
+  }
+
+  /**
+   * Internal helper to return a modifiable map containing all the fields.
+   * The returned Map is modifialbe so that the caller can add additional
+   * extension fields to implement {@link #getAllFields()}.
+   *
+   * @param getBytesForString whether to generate ByteString for string fields
+   */
+  private Map<FieldDescriptor, Object> getAllFieldsMutable(
+      boolean getBytesForString) {
+    final TreeMap<FieldDescriptor, Object> result =
+      new TreeMap<FieldDescriptor, Object>();
+    final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+    final List<FieldDescriptor> fields = descriptor.getFields();
+
+    for (int i = 0; i < fields.size(); i++) {
+      FieldDescriptor field = fields.get(i);
+      final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+      /*
+       * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+       * and it is not repeated. There is no need to iterate through the others.
+       */
+      if (oneofDescriptor != null) {
+        // Skip other fields in the Oneof we know are not set
+        i += oneofDescriptor.getFieldCount() - 1;
+        if (!hasOneof(oneofDescriptor)) {
+          // If no field is set in the Oneof, skip all the fields in the Oneof
+          continue;
+        }
+        // Get the pointer to the only field which is set in the Oneof
+        field = getOneofFieldDescriptor(oneofDescriptor);
+      } else {
+        // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+        if (field.isRepeated()) {
+          final List<?> value = (List<?>) getField(field);
+          if (!value.isEmpty()) {
+            result.put(field, value);
+          }
+          continue;
+        }
+        if (!hasField(field)) {
+          continue;
+        }
+      }
+      // Add the field to the map
+      if (getBytesForString && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+        result.put(field, getFieldRaw(field));
+      } else {
+        result.put(field, getField(field));
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+      // Check that all required fields are present.
+      if (field.isRequired()) {
+        if (!hasField(field)) {
+          return false;
+        }
+      }
+      // Check that embedded messages are initialized.
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          @SuppressWarnings("unchecked") final
+          List<Message> messageList = (List<Message>) getField(field);
+          for (final Message element : messageList) {
+            if (!element.isInitialized()) {
+              return false;
+            }
+          }
+        } else {
+          if (hasField(field) && !((Message) getField(field)).isInitialized()) {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  @Override
+  public Map<FieldDescriptor, Object> getAllFields() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ false));
+  }
+
+  /**
+   * Returns a collection of all the fields in this message which are set
+   * and their corresponding values.  A singular ("required" or "optional")
+   * field is set iff hasField() returns true for that field.  A "repeated"
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
+   * values are exactly what would be returned by calling
+   * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field.  The map
+   * is guaranteed to be a sorted map, so iterating over it will return fields
+   * in order by field number.
+   */
+  Map<FieldDescriptor, Object> getAllFieldsRaw() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ true));
+  }
+
+  @Override
+  public boolean hasOneof(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+  }
+
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+  }
+
+  @Override
+  public boolean hasField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).has(this);
+  }
+
+  @Override
+  public Object getField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).get(this);
+  }
+
+  /**
+   * Obtains the value of the given field, or the default value if it is
+   * not set.  For primitive fields, the boxed primitive value is returned.
+   * For enum fields, the EnumValueDescriptor for the value is returned. For
+   * embedded message fields, the sub-message is returned.  For repeated
+   * fields, a java.util.List is returned. For present string fields, a
+   * ByteString is returned representing the bytes that the field contains.
+   */
+  Object getFieldRaw(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).getRaw(this);
+  }
+
+  @Override
+  public int getRepeatedFieldCount(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeatedCount(this);
+  }
+
+  @Override
+  public Object getRepeatedField(final FieldDescriptor field, final int index) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeated(this, index);
+  }
+
+  @Override
+  public UnknownFieldSet getUnknownFields() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+  /**
+   * Called by subclasses to parse an unknown field.
+   *
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  protected boolean parseUnknownField(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      int tag)
+      throws IOException {
+    if (input.shouldDiscardUnknownFields()) {
+      return input.skipField(tag);
+    }
+    return unknownFields.mergeFieldFrom(tag, input);
+  }
+
+  protected boolean parseUnknownFieldProto3(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      int tag)
+      throws IOException {
+    if (input.shouldDiscardUnknownFieldsProto3()) {
+      return input.skipField(tag);
+    }
+    return unknownFields.mergeFieldFrom(tag, input);
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
+      throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input,
+      ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input) throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+  
+  protected static boolean canUseUnsafe() {
+    return UnsafeUtil.hasUnsafeArrayOperations() && UnsafeUtil.hasUnsafeByteBufferOperations();
+  }
+
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
+  }
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) {
+      return size;
+    }
+
+    memoizedSize = MessageReflection.getSerializedSize(
+        this, getAllFieldsRaw());
+    return memoizedSize;
+  }
+
+
+
+  /**
+   * Used by parsing constructors in generated classes.
+   */
+  protected void makeExtensionsImmutable() {
+    // Noop for messages without extensions.
+  }
+
+  /**
+   * TODO(xiaofeng): remove this after b/29368482 is fixed. We need to move this
+   * interface to AbstractMessage in order to versioning GeneratedMessageV3 but
+   * this move breaks binary compatibility for AppEngine. After AppEngine is
+   * fixed we can exlude this from google3.
+   */
+  protected interface BuilderParent extends AbstractMessage.BuilderParent {}
+
+  /**
+   * TODO(xiaofeng): remove this together with GeneratedMessageV3.BuilderParent.
+   */
+  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
+
+  @Override
+  protected Message.Builder newBuilderForType(final AbstractMessage.BuilderParent parent) {
+    return newBuilderForType(new BuilderParent() {
+      @Override
+      public void markDirty() {
+        parent.markDirty();
+      }
+    });
+  }
+
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder <BuilderType extends Builder<BuilderType>>
+      extends AbstractMessage.Builder<BuilderType> {
+
+    private BuilderParent builderParent;
+
+    private BuilderParentImpl meAsParent;
+
+    // Indicates that we've built a message and so we are now obligated
+    // to dispatch dirty invalidations. See GeneratedMessageV3.BuilderListener.
+    private boolean isClean;
+
+    private UnknownFieldSet unknownFields =
+        UnknownFieldSet.getDefaultInstance();
+
+    protected Builder() {
+      this(null);
+    }
+
+    protected Builder(BuilderParent builderParent) {
+      this.builderParent = builderParent;
+    }
+
+    @Override
+    void dispose() {
+      builderParent = null;
+    }
+
+    /**
+     * Called by the subclass when a message is built.
+     */
+    protected void onBuilt() {
+      if (builderParent != null) {
+        markClean();
+      }
+    }
+
+    /**
+     * Called by the subclass or a builder to notify us that a message was
+     * built and may be cached and therefore invalidations are needed.
+     */
+    @Override
+    protected void markClean() {
+      this.isClean = true;
+    }
+
+    /**
+     * Gets whether invalidations are needed
+     *
+     * @return whether invalidations are needed
+     */
+    protected boolean isClean() {
+      return isClean;
+    }
+
+    @Override
+    public BuilderType clone() {
+      BuilderType builder =
+          (BuilderType) getDefaultInstanceForType().newBuilderForType();
+      builder.mergeFrom(buildPartial());
+      return builder;
+    }
+
+    /**
+     * Called by the initialization and clear code paths to allow subclasses to
+     * reset any of their builtin fields back to the initial values.
+     */
+    @Override
+    public BuilderType clear() {
+      unknownFields = UnknownFieldSet.getDefaultInstance();
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /**
+     * Get the FieldAccessorTable for this type.  We can't have the message
+     * class pass this in to the constructor because of bootstrapping trouble
+     * with DescriptorProtos.
+     */
+    protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+    @Override
+    public Descriptor getDescriptorForType() {
+      return internalGetFieldAccessorTable().descriptor;
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      return Collections.unmodifiableMap(getAllFieldsMutable());
+    }
+
+    /** Internal helper which returns a mutable map. */
+    private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+      final TreeMap<FieldDescriptor, Object> result =
+        new TreeMap<FieldDescriptor, Object>();
+      final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+      final List<FieldDescriptor> fields = descriptor.getFields();
+
+      for (int i = 0; i < fields.size(); i++) {
+        FieldDescriptor field = fields.get(i);
+        final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+        /*
+         * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+         * and it is not repeated. There is no need to iterate through the others.
+         */
+        if (oneofDescriptor != null) {
+          // Skip other fields in the Oneof we know are not set
+          i += oneofDescriptor.getFieldCount() - 1;
+          if (!hasOneof(oneofDescriptor)) {
+            // If no field is set in the Oneof, skip all the fields in the Oneof
+            continue;
+          }
+          // Get the pointer to the only field which is set in the Oneof
+          field = getOneofFieldDescriptor(oneofDescriptor);
+        } else {
+          // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+          if (field.isRepeated()) {
+            final List<?> value = (List<?>) getField(field);
+            if (!value.isEmpty()) {
+              result.put(field, value);
+            }
+            continue;
+          }
+          if (!hasField(field)) {
+            continue;
+          }
+        }
+        // Add the field to the map
+        result.put(field, getField(field));
+      }
+      return result;
+    }
+
+    @Override
+    public Message.Builder newBuilderForField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).newBuilder();
+    }
+
+    @Override
+    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).getBuilder(this);
+    }
+
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
+      return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
+          this, index);
+    }
+
+    @Override
+    public boolean hasOneof(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+    }
+
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).has(this);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      Object object = internalGetFieldAccessorTable().getField(field).get(this);
+      if (field.isRepeated()) {
+        // The underlying list object is still modifiable at this point.
+        // Make sure not to expose the modifiable list to the caller.
+        return Collections.unmodifiableList((List) object);
+      } else {
+        return object;
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).set(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      internalGetFieldAccessorTable().getField(field).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearOneof(final OneofDescriptor oneof) {
+      internalGetFieldAccessorTable().getOneof(oneof).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeatedCount(this);
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field, final int index) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeated(this, index);
+    }
+
+    @Override
+    public BuilderType setRepeatedField(
+        final FieldDescriptor field, final int index, final Object value) {
+      internalGetFieldAccessorTable().getField(field)
+        .setRepeated(this, index, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
+      this.unknownFields = unknownFields;
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) {
+      if (CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
+        return (BuilderType) this;
+      }
+      this.unknownFields = unknownFields;
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeUnknownFields(
+        final UnknownFieldSet unknownFields) {
+      return setUnknownFields(
+        UnknownFieldSet.newBuilder(this.unknownFields)
+                       .mergeFrom(unknownFields)
+                       .build());
+    }
+
+
+    @Override
+    public boolean isInitialized() {
+      for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+        // Check that all required fields are present.
+        if (field.isRequired()) {
+          if (!hasField(field)) {
+            return false;
+          }
+        }
+        // Check that embedded messages are initialized.
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (field.isRepeated()) {
+            @SuppressWarnings("unchecked") final
+            List<Message> messageList = (List<Message>) getField(field);
+            for (final Message element : messageList) {
+              if (!element.isInitialized()) {
+                return false;
+              }
+            }
+          } else {
+            if (hasField(field) &&
+                !((Message) getField(field)).isInitialized()) {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    }
+
+    @Override
+    public final UnknownFieldSet getUnknownFields() {
+      return unknownFields;
+    }
+
+    /**
+     * Implementation of {@link BuilderParent} for giving to our children. This
+     * small inner class makes it so we don't publicly expose the BuilderParent
+     * methods.
+     */
+    private class BuilderParentImpl implements BuilderParent {
+
+      @Override
+      public void markDirty() {
+        onChanged();
+      }
+    }
+
+    /**
+     * Gets the {@link BuilderParent} for giving to our children.
+     * @return The builder parent for our children.
+     */
+    protected BuilderParent getParentForChildren() {
+      if (meAsParent == null) {
+        meAsParent = new BuilderParentImpl();
+      }
+      return meAsParent;
+    }
+
+    /**
+     * Called when a the builder or one of its nested children has changed
+     * and any parent should be notified of its invalidation.
+     */
+    protected final void onChanged() {
+      if (isClean && builderParent != null) {
+        builderParent.markDirty();
+
+        // Don't keep dispatching invalidations until build is called again.
+        isClean = false;
+      }
+    }
+
+    /**
+     * Gets the map field with the given field number. This method should be
+     * overridden in the generated message class if the message contains map
+     * fields.
+     *
+     * Unlike other field types, reflection support for map fields can't be
+     * implemented based on generated public API because we need to access a
+     * map field as a list in reflection API but the generated API only allows
+     * us to access it as a map. This method returns the underlying map field
+     * directly and thus enables us to access the map field as a list.
+     */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+
+    /** Like {@link #internalGetMapField} but return a mutable version. */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMutableMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+  }
+
+  // =================================================================
+  // Extensions-related stuff
+
+  public interface ExtendableMessageOrBuilder<
+      MessageType extends ExtendableMessage> extends MessageOrBuilder {
+    // Re-define for return type covariance.
+    @Override
+    Message getDefaultInstanceForType();
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        ExtensionLite<MessageType, List<Type>> extension);
+
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, List<Type>> extension,
+        int index);
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        Extension<MessageType, Type> extension);
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        Extension<MessageType, List<Type>> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        GeneratedExtension<MessageType, List<Type>> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, Type> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, List<Type>> extension,
+        int index);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, List<Type>> extension,
+        int index);
+  }
+
+  /**
+   * Generated message classes for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "has", "get", and "getCount" -- but for extensions.  The extensions
+   * are identified using instances of the class {@link GeneratedExtension};
+   * the protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo = getFoo();
+   * int i = foo.getExtension(MyProto.bar);
+   * </pre>
+   *
+   * <p>See also {@link ExtendableBuilder}.
+   */
+  public abstract static class ExtendableMessage<
+        MessageType extends ExtendableMessage>
+      extends GeneratedMessageV3
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final FieldSet<FieldDescriptor> extensions;
+
+    protected ExtendableMessage() {
+      this.extensions = FieldSet.newFieldSet();
+    }
+
+    protected ExtendableMessage(
+        ExtendableBuilder<MessageType, ?> builder) {
+      super(builder);
+      this.extensions = builder.buildExtensions();
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    @Override
+    protected boolean parseUnknownField(
+        CodedInputStream input,
+        UnknownFieldSet.Builder unknownFields,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input, input.shouldDiscardUnknownFields() ? null : unknownFields, extensionRegistry,
+          getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag);
+    }
+
+    @Override
+    protected boolean parseUnknownFieldProto3(
+        CodedInputStream input,
+        UnknownFieldSet.Builder unknownFields,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input,
+          input.shouldDiscardUnknownFieldsProto3() ? null : unknownFields,
+          extensionRegistry,
+          getDescriptorForType(),
+          new MessageReflection.ExtensionAdapter(extensions),
+          tag);
+    }
+
+
+    /**
+     * Used by parsing constructors in generated classes.
+     */
+    @Override
+    protected void makeExtensionsImmutable() {
+      extensions.makeImmutable();
+    }
+
+    /**
+     * Used by subclasses to serialize extensions.  Extension ranges may be
+     * interleaved with field numbers, but we must write them in canonical
+     * (sorted by field number) order.  ExtensionWriter helps us write
+     * individual ranges of extensions at once.
+     */
+    protected class ExtensionWriter {
+      // Imagine how much simpler this code would be if Java iterators had
+      // a way to get the next element without advancing the iterator.
+
+      private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
+        extensions.iterator();
+      private Map.Entry<FieldDescriptor, Object> next;
+      private final boolean messageSetWireFormat;
+
+      private ExtensionWriter(final boolean messageSetWireFormat) {
+        if (iter.hasNext()) {
+          next = iter.next();
+        }
+        this.messageSetWireFormat = messageSetWireFormat;
+      }
+
+      public void writeUntil(final int end, final CodedOutputStream output)
+                             throws IOException {
+        while (next != null && next.getKey().getNumber() < end) {
+          FieldDescriptor descriptor = next.getKey();
+          if (messageSetWireFormat && descriptor.getLiteJavaType() ==
+                  WireFormat.JavaType.MESSAGE &&
+              !descriptor.isRepeated()) {
+            if (next instanceof LazyField.LazyEntry<?>) {
+              output.writeRawMessageSetExtension(descriptor.getNumber(),
+                  ((LazyField.LazyEntry<?>) next).getField().toByteString());
+            } else {
+              output.writeMessageSetExtension(descriptor.getNumber(),
+                                              (Message) next.getValue());
+            }
+          } else {
+            // TODO(xiangl): Taken care of following code, it may cause
+            // problem when we use LazyField for normal fields/extensions.
+            // Due to the optional field can be duplicated at the end of
+            // serialized bytes, which will make the serialized size change
+            // after lazy field parsed. So when we use LazyField globally,
+            // we need to change the following write method to write cached
+            // bytes directly rather than write the parsed message.
+            FieldSet.writeField(descriptor, next.getValue(), output);
+          }
+          if (iter.hasNext()) {
+            next = iter.next();
+          } else {
+            next = null;
+          }
+        }
+      }
+    }
+
+    protected ExtensionWriter newExtensionWriter() {
+      return new ExtensionWriter(false);
+    }
+    protected ExtensionWriter newMessageSetExtensionWriter() {
+      return new ExtensionWriter(true);
+    }
+
+    /** Called by subclasses to compute the size of extensions. */
+    protected int extensionsSerializedSize() {
+      return extensions.getSerializedSize();
+    }
+    protected int extensionsSerializedSizeAsMessageSet() {
+      return extensions.getMessageSetSerializedSize();
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    protected Map<FieldDescriptor, Object> getExtensionFields() {
+      return extensions.getAllFields();
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFieldsRaw() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.isRepeated()) {
+            return Collections.emptyList();
+          } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  /**
+   * Generated message builders for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "get", "set", and "add" -- but for extensions.  The extensions are
+   * identified using instances of the class {@link GeneratedExtension}; the
+   * protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo =
+   *   MyProto.Foo.newBuilder()
+   *     .setExtension(MyProto.bar, 123)
+   *     .build();
+   * </pre>
+   *
+   * <p>See also {@link ExtendableMessage}.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class ExtendableBuilder<
+        MessageType extends ExtendableMessage,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+      extends Builder<BuilderType>
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
+
+    protected ExtendableBuilder() {}
+
+    protected ExtendableBuilder(
+        BuilderParent parent) {
+      super(parent);
+    }
+
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
+    @Override
+    public BuilderType clear() {
+      extensions = FieldSet.emptySet();
+      return super.clear();
+    }
+
+    private void ensureExtensionsIsMutable() {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, Type> extensionLite,
+        final Type value) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setField(descriptor, extension.toReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final int index, final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setRepeatedField(
+        descriptor, index,
+        extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.addRepeatedField(
+          descriptor, extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final ExtensionLite<MessageType, ?> extensionLite) {
+      Extension<MessageType, ?> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      extensions.clearField(extension.getDescriptor());
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of an extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final Extension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Append a value to a repeated extension. */
+    public <Type> BuilderType addExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final Extension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+    /** Clear an extension. */
+    public <Type> BuilderType clearExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    /**
+     * Called by the build code path to create a copy of the extensions for
+     * building the message.
+     */
+    private FieldSet<FieldDescriptor> buildExtensions() {
+      extensions.makeImmutable();
+      return extensions;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+      result.putAll(extensions.getAllFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field,
+                                final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setField(field, value);
+      }
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.clearField(field);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.clearField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setRepeatedField(final FieldDescriptor field,
+                                        final int index, final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setRepeatedField(field, index, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setRepeatedField(field, index, value);
+      }
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field,
+                                        final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.addRepeatedField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.addRepeatedField(field, value);
+      }
+    }
+
+    protected final void mergeExtensionFields(final ExtendableMessage other) {
+      ensureExtensionsIsMutable();
+      extensions.mergeFrom(other.extensions);
+      onChanged();
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Gets the descriptor for an extension. The implementation depends on whether
+   * the extension is scoped in the top level of a file or scoped in a Message.
+   */
+  static interface ExtensionDescriptorRetriever {
+    FieldDescriptor getDescriptor();
+  }
+
+
+  // =================================================================
+
+  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+  @SuppressWarnings("unchecked")
+  private static Method getMethodOrDie(
+      final Class clazz, final String name, final Class... params) {
+    try {
+      return clazz.getMethod(name, params);
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(
+        "Generated message class \"" + clazz.getName() +
+        "\" missing method \"" + name + "\".", e);
+    }
+  }
+
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  private static Object invokeOrDie(
+      final Method method, final Object object, final Object... params) {
+    try {
+      return method.invoke(object, params);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(
+        "Couldn't use Java reflection to implement protocol message " +
+        "reflection.", e);
+    } catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof RuntimeException) {
+        throw (RuntimeException) cause;
+      } else if (cause instanceof Error) {
+        throw (Error) cause;
+      } else {
+        throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", cause);
+      }
+    }
+  }
+
+  /**
+   * Gets the map field with the given field number. This method should be
+   * overridden in the generated message class if the message contains map
+   * fields.
+   *
+   * Unlike other field types, reflection support for map fields can't be
+   * implemented based on generated public API because we need to access a
+   * map field as a list in reflection API but the generated API only allows
+   * us to access it as a map. This method returns the underlying map field
+   * directly and thus enables us to access the map field as a list.
+   */
+  @SuppressWarnings({"rawtypes", "unused"})
+  protected MapField internalGetMapField(int fieldNumber) {
+    // Note that we can't use descriptor names here because this method will
+    // be called when descriptor is being initialized.
+    throw new RuntimeException(
+        "No map fields found in " + getClass().getName());
+  }
+
+  /**
+   * Users should ignore this class.  This class provides the implementation
+   * with access to the fields of a message object using Java reflection.
+   */
+  public static final class FieldAccessorTable {
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class.  Only
+     * one FieldAccessorTable should ever be constructed per class.
+     *
+     * @param descriptor     The type's descriptor.
+     * @param camelCaseNames The camelcase names of all fields in the message.
+     *                       These are used to derive the accessor method names.
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames,
+        final Class<? extends GeneratedMessageV3> messageClass,
+        final Class<? extends Builder> builderClass) {
+      this(descriptor, camelCaseNames);
+      ensureFieldAccessorsInitialized(messageClass, builderClass);
+    }
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class without
+     * initializing FieldAccessors.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames) {
+      this.descriptor = descriptor;
+      this.camelCaseNames = camelCaseNames;
+      fields = new FieldAccessor[descriptor.getFields().size()];
+      oneofs = new OneofAccessor[descriptor.getOneofs().size()];
+      initialized = false;
+    }
+
+    /**
+     * Ensures the field accessors are initialized. This method is thread-safe.
+     *
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     * @return this
+     */
+    public FieldAccessorTable ensureFieldAccessorsInitialized(
+        Class<? extends GeneratedMessageV3> messageClass,
+        Class<? extends Builder> builderClass) {
+      if (initialized) { return this; }
+      synchronized (this) {
+        if (initialized) { return this; }
+        int fieldsSize = fields.length;
+        for (int i = 0; i < fieldsSize; i++) {
+          FieldDescriptor field = descriptor.getFields().get(i);
+          String containingOneofCamelCaseName = null;
+          if (field.getContainingOneof() != null) {
+            containingOneofCamelCaseName =
+                camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
+          }
+          if (field.isRepeated()) {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              if (field.isMapField()) {
+                fields[i] = new MapFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              } else {
+                fields[i] = new RepeatedMessageFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              }
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new RepeatedEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            } else {
+              fields[i] = new RepeatedFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            }
+          } else {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              fields[i] = new SingularMessageFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new SingularEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+              fields[i] = new SingularStringFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else {
+              fields[i] = new SingularFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            }
+          }
+        }
+
+        int oneofsSize = oneofs.length;
+        for (int i = 0; i < oneofsSize; i++) {
+          oneofs[i] = new OneofAccessor(
+              descriptor, camelCaseNames[i + fieldsSize],
+              messageClass, builderClass);
+        }
+        initialized = true;
+        camelCaseNames = null;
+        return this;
+      }
+    }
+
+    private final Descriptor descriptor;
+    private final FieldAccessor[] fields;
+    private String[] camelCaseNames;
+    private final OneofAccessor[] oneofs;
+    private volatile boolean initialized;
+
+    /** Get the FieldAccessor for a particular field. */
+    private FieldAccessor getField(final FieldDescriptor field) {
+      if (field.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      } else if (field.isExtension()) {
+        // If this type had extensions, it would subclass ExtendableMessage,
+        // which overrides the reflection interface to handle extensions.
+        throw new IllegalArgumentException(
+          "This type does not have extensions.");
+      }
+      return fields[field.getIndex()];
+    }
+
+    /** Get the OneofAccessor for a particular oneof. */
+    private OneofAccessor getOneof(final OneofDescriptor oneof) {
+      if (oneof.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+      return oneofs[oneof.getIndex()];
+    }
+
+    /**
+     * Abstract interface that provides access to a single field.  This is
+     * implemented differently depending on the field type and cardinality.
+     */
+    private interface FieldAccessor {
+      Object get(GeneratedMessageV3 message);
+      Object get(GeneratedMessageV3.Builder builder);
+      Object getRaw(GeneratedMessageV3 message);
+      Object getRaw(GeneratedMessageV3.Builder builder);
+      void set(Builder builder, Object value);
+      Object getRepeated(GeneratedMessageV3 message, int index);
+      Object getRepeated(GeneratedMessageV3.Builder builder, int index);
+      Object getRepeatedRaw(GeneratedMessageV3 message, int index);
+      Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index);
+      void setRepeated(Builder builder,
+                       int index, Object value);
+      void addRepeated(Builder builder, Object value);
+      boolean has(GeneratedMessageV3 message);
+      boolean has(GeneratedMessageV3.Builder builder);
+      int getRepeatedCount(GeneratedMessageV3 message);
+      int getRepeatedCount(GeneratedMessageV3.Builder builder);
+      void clear(Builder builder);
+      Message.Builder newBuilder();
+      Message.Builder getBuilder(GeneratedMessageV3.Builder builder);
+      Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder,
+                                         int index);
+    }
+
+    /** OneofAccessor provides access to a single oneof. */
+    private static class OneofAccessor {
+      OneofAccessor(
+          final Descriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        this.descriptor = descriptor;
+        caseMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
+        caseMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      private final Descriptor descriptor;
+      private final Method caseMethod;
+      private final Method caseMethodBuilder;
+      private final Method clearMethod;
+
+      public boolean has(final GeneratedMessageV3 message) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public FieldDescriptor get(final GeneratedMessageV3 message) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public FieldDescriptor get(GeneratedMessageV3.Builder builder) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+    }
+
+    private static boolean supportFieldPresence(FileDescriptor file) {
+      return file.getSyntax() == FileDescriptor.Syntax.PROTO2;
+    }
+
+    // ---------------------------------------------------------------
+
+    private static class SingularFieldAccessor implements FieldAccessor {
+      SingularFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        field = descriptor;
+        isOneofField = descriptor.getContainingOneof() != null;
+        hasHasMethod = supportFieldPresence(descriptor.getFile())
+            || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
+        getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+        getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
+        type = getMethod.getReturnType();
+        setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+        hasMethod =
+            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
+        hasMethodBuilder =
+            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+        caseMethod = isOneofField ? getMethodOrDie(
+            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
+        caseMethodBuilder = isOneofField ? getMethodOrDie(
+            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
+      }
+
+      // Note:  We use Java reflection to call public methods rather than
+      //   access private fields directly as this avoids runtime security
+      //   checks.
+      protected final Class<?> type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method setMethod;
+      protected final Method hasMethod;
+      protected final Method hasMethodBuilder;
+      protected final Method clearMethod;
+      protected final Method caseMethod;
+      protected final Method caseMethodBuilder;
+      protected final FieldDescriptor field;
+      protected final boolean isOneofField;
+      protected final boolean hasHasMethod;
+
+      private int getOneofFieldNumber(final GeneratedMessageV3 message) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+      }
+
+      private int getOneofFieldNumber(final GeneratedMessageV3.Builder builder) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        invokeOrDie(setMethod, builder, value);
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(final GeneratedMessageV3 message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        throw new UnsupportedOperationException(
+          "setRepeatedField() called on a singular field.");
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        throw new UnsupportedOperationException(
+          "addRepeatedField() called on a singular field.");
+      }
+      @Override
+      public boolean has(final GeneratedMessageV3 message) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(message) == field.getNumber();
+          }
+          return !get(message).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethod, message);
+      }
+      @Override
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(builder) == field.getNumber();
+          }
+          return !get(builder).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethodBuilder, builder);
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class RepeatedFieldAccessor implements FieldAccessor {
+      protected final Class type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method getRepeatedMethod;
+      protected final Method getRepeatedMethodBuilder;
+      protected final Method setRepeatedMethod;
+      protected final Method addRepeatedMethod;
+      protected final Method getCountMethod;
+      protected final Method getCountMethodBuilder;
+      protected final Method clearMethod;
+
+      RepeatedFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        getMethod = getMethodOrDie(messageClass,
+                                   "get" + camelCaseName + "List");
+        getMethodBuilder = getMethodOrDie(builderClass,
+                                   "get" + camelCaseName + "List");
+        getRepeatedMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+        getRepeatedMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
+        type = getRepeatedMethod.getReturnType();
+        setRepeatedMethod =
+            getMethodOrDie(builderClass, "set" + camelCaseName,
+                           Integer.TYPE, type);
+        addRepeatedMethod =
+            getMethodOrDie(builderClass, "add" + camelCaseName, type);
+        getCountMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+        getCountMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
+
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        // Add all the elements individually.  This serves two purposes:
+        // 1) Verifies that each element has the correct type.
+        // 2) Insures that the caller cannot modify the list later on and
+        //    have the modifications be reflected in the message.
+        clear(builder);
+        for (final Object element : (List<?>) value) {
+          addRepeated(builder, element);
+        }
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message, final int index) {
+        return invokeOrDie(getRepeatedMethod, message, index);
+      }
+      @Override
+      public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
+        return invokeOrDie(getRepeatedMethodBuilder, builder, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
+        return getRepeated(message, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        invokeOrDie(setRepeatedMethod, builder, index, value);
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        invokeOrDie(addRepeatedMethod, builder, value);
+      }
+      @Override
+      public boolean has(final GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessageV3 message) {
+        return (Integer) invokeOrDie(getCountMethod, message);
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
+        return (Integer) invokeOrDie(getCountMethodBuilder, builder);
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class MapFieldAccessor implements FieldAccessor {
+      MapFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        field = descriptor;
+        Method getDefaultInstanceMethod =
+            getMethodOrDie(messageClass, "getDefaultInstance");
+        MapField defaultMapField = getMapField(
+            (GeneratedMessageV3) invokeOrDie(getDefaultInstanceMethod, null));
+        mapEntryMessageDefaultInstance =
+            defaultMapField.getMapEntryMessageDefaultInstance();
+      }
+
+      private final FieldDescriptor field;
+      private final Message mapEntryMessageDefaultInstance;
+
+      private MapField<?, ?> getMapField(GeneratedMessageV3 message) {
+        return (MapField<?, ?>) message.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMapField(GeneratedMessageV3.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMutableMapField(
+          GeneratedMessageV3.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMutableMapField(
+            field.getNumber());
+      }
+
+      private Message coerceType(Message value) {
+        if (value == null) {
+          return null;
+        }
+        if (mapEntryMessageDefaultInstance.getClass().isInstance(value)) {
+          return value;
+        }
+        // The value is not the exact right message type.  However, if it
+        // is an alternative implementation of the same type -- e.g. a
+        // DynamicMessage -- we should accept it.  In this case we can make
+        // a copy of the message.
+        return mapEntryMessageDefaultInstance.toBuilder().mergeFrom(value).build();
+      }
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(GeneratedMessageV3 message) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(message); i++) {
+          result.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(Builder builder) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(builder); i++) {
+          result.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3 message) {
+        return get(message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+
+      @Override
+      public void set(Builder builder, Object value) {
+        clear(builder);
+        for (Object entry : (List) value) {
+          addRepeated(builder, entry);
+        }
+      }
+
+      @Override
+      public Object getRepeated(GeneratedMessageV3 message, int index) {
+        return getMapField(message).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeated(Builder builder, int index) {
+        return getMapField(builder).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
+        return getRepeated(message, index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+
+      @Override
+      public void setRepeated(Builder builder, int index, Object value) {
+        getMutableMapField(builder).getMutableList().set(index, coerceType((Message) value));
+      }
+
+      @Override
+      public void addRepeated(Builder builder, Object value) {
+        getMutableMapField(builder).getMutableList().add(coerceType((Message) value));
+      }
+
+      @Override
+      public boolean has(GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public boolean has(Builder builder) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3 message) {
+        return getMapField(message).getList().size();
+      }
+
+      @Override
+      public int getRepeatedCount(Builder builder) {
+        return getMapField(builder).getList().size();
+      }
+
+      @Override
+      public void clear(Builder builder) {
+        getMutableMapField(builder).getMutableList().clear();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder newBuilder() {
+        return mapEntryMessageDefaultInstance.newBuilderForType();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularEnumFieldAccessor
+        extends SingularFieldAccessor {
+      SingularEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
+          getValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
+          setValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class);
+        }
+      }
+
+      private EnumDescriptor enumDescriptor;
+
+      private Method valueOfMethod;
+      private Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getValueMethod;
+      private Method getValueMethodBuilder;
+      private Method setValueMethod;
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethod, message);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(message));
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3.Builder builder) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethodBuilder, builder);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(builder));
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.set(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    private static final class RepeatedEnumFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getRepeatedValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
+          getRepeatedValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value", int.class);
+          setRepeatedValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class, int.class);
+          addRepeatedValueMethod =
+              getMethodOrDie(builderClass, "add" + camelCaseName + "Value", int.class);
+        }
+      }
+      private EnumDescriptor enumDescriptor;
+
+      private final Method valueOfMethod;
+      private final Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getRepeatedValueMethod;
+      private Method getRepeatedValueMethodBuilder;
+      private Method setRepeatedValueMethod;
+      private Method addRepeatedValueMethod;
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessageV3 message) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(message);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessageV3.Builder builder) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(builder);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(message, index));
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3.Builder builder,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(builder, index));
+      }
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setRepeatedValueMethod, builder, index,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
+                          value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(addRepeatedValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    /**
+     * Field accessor for string fields.
+     *
+     * <p>This class makes getFooBytes() and setFooBytes() available for
+     * reflection API so that reflection based serialize/parse functions can
+     * access the raw bytes of the field to preserve non-UTF8 bytes in the
+     * string.
+     *
+     * <p>This ensures the serialize/parse round-trip safety, which is important
+     * for servers which forward messages.
+     */
+    private static final class SingularStringFieldAccessor
+        extends SingularFieldAccessor {
+      SingularStringFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+        getBytesMethod = getMethodOrDie(messageClass,
+            "get" + camelCaseName + "Bytes");
+        getBytesMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Bytes");
+        setBytesMethodBuilder = getMethodOrDie(builderClass,
+            "set" + camelCaseName + "Bytes", ByteString.class);
+      }
+
+      private final Method getBytesMethod;
+      private final Method getBytesMethodBuilder;
+      private final Method setBytesMethodBuilder;
+
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return invokeOrDie(getBytesMethod, message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getBytesMethodBuilder, builder);
+      }
+
+      @Override
+      public void set(GeneratedMessageV3.Builder builder, Object value) {
+        if (value instanceof ByteString) {
+          invokeOrDie(setBytesMethodBuilder, builder, value);
+        } else {
+          super.set(builder, value);
+        }
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularMessageFieldAccessor
+        extends SingularFieldAccessor {
+      SingularMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).buildPartial();
+        }
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        super.set(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
+      }
+    }
+
+    private static final class RepeatedMessageFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Builder", Integer.TYPE);
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).build();
+        }
+      }
+
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        super.setRepeated(builder, index, coerceType(value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        super.addRepeated(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(
+          final GeneratedMessageV3.Builder builder, final int index) {
+        return (Message.Builder) invokeOrDie(
+            getBuilderMethodBuilder, builder, index);
+      }
+    }
+  }
+
+  /**
+   * Replaces this object in the output stream with a serialized form.
+   * Part of Java's serialization magic.  Generated sub-classes must override
+   * this method by calling {@code return super.writeReplace();}
+   * @return a SerializedForm of this message
+   */
+  protected Object writeReplace() throws ObjectStreamException {
+    return new GeneratedMessageLite.SerializedForm(this);
+  }
+
+  /**
+   * Checks that the {@link Extension} is non-Lite and returns it as a
+   * {@link GeneratedExtension}.
+   */
+  private static <MessageType extends ExtendableMessage<MessageType>, T>
+    Extension<MessageType, T> checkNotLite(
+        ExtensionLite<MessageType, T> extension) {
+    if (extension.isLite()) {
+      throw new IllegalArgumentException("Expected non-lite extension.");
+    }
+
+    return (Extension<MessageType, T>) extension;
+  }
+
+  protected static int computeStringSize(final int fieldNumber, final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
+    } else {
+      return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
+    }
+  }
+
+  protected static int computeStringSizeNoTag(final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSizeNoTag((String) value);
+    } else {
+      return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+    }
+  }
+
+  protected static void writeString(
+      CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeString(fieldNumber, (String) value);
+    } else {
+      output.writeBytes(fieldNumber, (ByteString) value);
+    }
+  }
+
+  protected static void writeStringNoTag(
+      CodedOutputStream output, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeStringNoTag((String) value);
+    } else {
+      output.writeBytesNoTag((ByteString) value);
+    }
+  }
+
+  protected static <V> void serializeIntegerMapTo(
+      CodedOutputStream out,
+      MapField<Integer, V> field,
+      MapEntry<Integer, V> defaultEntry,
+      int fieldNumber) throws IOException {
+    Map<Integer, V> m = field.getMap();
+    if (!out.isSerializationDeterministic()) {
+      serializeMapTo(out, m, defaultEntry, fieldNumber);
+      return;
+    }
+    // Sorting the unboxed keys and then look up the values during serialziation is 2x faster
+    // than sorting map entries with a custom comparator directly.
+    int[] keys = new int[m.size()];
+    int index = 0;
+    for (int k : m.keySet()) {
+      keys[index++] = k;
+    }
+    Arrays.sort(keys);
+    for (int key : keys) {
+      out.writeMessage(fieldNumber,
+          defaultEntry.newBuilderForType()
+              .setKey(key)
+              .setValue(m.get(key))
+              .build());
+    }
+  }
+
+  protected static <V> void serializeLongMapTo(
+      CodedOutputStream out,
+      MapField<Long, V> field,
+      MapEntry<Long, V> defaultEntry,
+      int fieldNumber)
+      throws IOException {
+    Map<Long, V> m = field.getMap();
+    if (!out.isSerializationDeterministic()) {
+      serializeMapTo(out, m, defaultEntry, fieldNumber);
+      return;
+    }
+
+    long[] keys = new long[m.size()];
+    int index = 0;
+    for (long k : m.keySet()) {
+      keys[index++] = k;
+    }
+    Arrays.sort(keys);
+    for (long key : keys) {
+      out.writeMessage(fieldNumber,
+          defaultEntry.newBuilderForType()
+              .setKey(key)
+              .setValue(m.get(key))
+              .build());
+    }
+  }
+
+  protected static <V> void serializeStringMapTo(
+      CodedOutputStream out,
+      MapField<String, V> field,
+      MapEntry<String, V> defaultEntry,
+      int fieldNumber)
+      throws IOException {
+    Map<String, V> m = field.getMap();
+    if (!out.isSerializationDeterministic()) {
+      serializeMapTo(out, m, defaultEntry, fieldNumber);
+      return;
+    }
+
+    // Sorting the String keys and then look up the values during serialziation is 25% faster than
+    // sorting map entries with a custom comparator directly.
+    String[] keys = new String[m.size()];
+    keys = m.keySet().toArray(keys);
+    Arrays.sort(keys);
+    for (String key : keys) {
+      out.writeMessage(fieldNumber,
+          defaultEntry.newBuilderForType()
+              .setKey(key)
+              .setValue(m.get(key))
+              .build());
+    }
+  }
+
+  protected static <V> void serializeBooleanMapTo(
+      CodedOutputStream out,
+      MapField<Boolean, V> field,
+      MapEntry<Boolean, V> defaultEntry,
+      int fieldNumber)
+      throws IOException {
+    Map<Boolean, V> m = field.getMap();
+    if (!out.isSerializationDeterministic()) {
+      serializeMapTo(out, m, defaultEntry, fieldNumber);
+      return;
+    }
+    maybeSerializeBooleanEntryTo(out, m, defaultEntry, fieldNumber, false);
+    maybeSerializeBooleanEntryTo(out, m, defaultEntry, fieldNumber, true);
+  }
+
+  private static <V> void maybeSerializeBooleanEntryTo(
+      CodedOutputStream out,
+      Map<Boolean, V> m,
+      MapEntry<Boolean, V> defaultEntry,
+      int fieldNumber,
+      boolean key)
+      throws IOException {
+    if (m.containsKey(key)) {
+      out.writeMessage(fieldNumber,
+          defaultEntry.newBuilderForType()
+              .setKey(key)
+              .setValue(m.get(key))
+              .build());
+    }
+  }
+
+  /** Serialize the map using the iteration order. */
+  private static <K, V> void serializeMapTo(
+      CodedOutputStream out,
+      Map<K, V> m,
+      MapEntry<K, V> defaultEntry,
+      int fieldNumber)
+      throws IOException {
+    for (Map.Entry<K, V> entry : m.entrySet()) {
+      out.writeMessage(fieldNumber,
+          defaultEntry.newBuilderForType()
+              .setKey(entry.getKey())
+              .setValue(entry.getValue())
+              .build());
+    }
+  }
+}
+
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index f4e68ed..aacd71e 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -30,36 +30,35 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.IntList;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.IntList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.RandomAccess;
 
 /**
  * An implementation of {@link IntList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
-  
-  private static final int DEFAULT_CAPACITY = 10;
-  
+final class IntArrayList extends AbstractProtobufList<Integer>
+    implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
+
   private static final IntArrayList EMPTY_LIST = new IntArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static IntArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private int[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -70,34 +69,70 @@
    * Constructs a new mutable {@code IntArrayList} with default capacity.
    */
   IntArrayList() {
-    this(DEFAULT_CAPACITY);
+    this(new int[DEFAULT_CAPACITY], 0);
   }
 
   /**
-   * Constructs a new mutable {@code IntArrayList} with the provided capacity.
+   * Constructs a new mutable {@code IntArrayList}
+   * containing the same elements as {@code other}.
    */
-  IntArrayList(int capacity) {
-    array = new int[capacity];
-    size = 0;
+  private IntArrayList(int[] other, int size) {
+    array = other;
+    this.size = size;
   }
 
-  /**
-   * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
-   */
-  IntArrayList(List<Integer> other) {
-    if (other instanceof IntArrayList) {
-      IntArrayList list = (IntArrayList) other;
-      array = list.array.clone();
-      size = list.size;
-    } else {
-      size = other.size();
-      array = new int[size];
-      for (int i = 0; i < size; i++) {
-        array[i] = other.get(i);
+  @Override
+  protected void removeRange(int fromIndex, int toIndex) {
+    ensureIsMutable();
+    if (toIndex < fromIndex) {
+      throw new IndexOutOfBoundsException("toIndex < fromIndex");
+    }
+
+    System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+    size -= (toIndex - fromIndex);
+    modCount++;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof IntArrayList)) {
+      return super.equals(o);
+    }
+    IntArrayList other = (IntArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+
+    final int[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
       }
     }
+
+    return true;
   }
-  
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + array[i];
+    }
+    return result;
+  }
+
+  @Override
+  public IntList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new IntArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
   @Override
   public Integer get(int index) {
     return getInt(index);
@@ -149,7 +184,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -157,10 +192,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       int[] newArray = new int[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -174,38 +209,36 @@
   @Override
   public boolean addAll(Collection<? extends Integer> collection) {
     ensureIsMutable();
-    
-    if (collection == null) {
-      throw new NullPointerException();
-    }
-    
+
+    checkNotNull(collection);
+
     // We specialize when adding another IntArrayList to avoid boxing elements.
     if (!(collection instanceof IntArrayList)) {
       return super.addAll(collection);
     }
-    
+
     IntArrayList list = (IntArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -225,7 +258,9 @@
     ensureIsMutable();
     ensureIndexInRange(index);
     int value = array[index];
-    System.arraycopy(array, index + 1, array, index, size - index);
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index);
+    }
     size--;
     modCount++;
     return value;
@@ -234,7 +269,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index e19b6dc..848cad0 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -41,6 +41,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.RandomAccess;
 import java.util.Set;
 
 /**
@@ -51,10 +52,32 @@
  *
  * @author kenton@google.com (Kenton Varda)
  */
-public class Internal {
+public final class Internal {
 
-  protected static final Charset UTF_8 = Charset.forName("UTF-8");
-  protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+  private Internal() {}
+
+  static final Charset UTF_8 = Charset.forName("UTF-8");
+  static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+  /**
+   * Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
+   */
+  static <T> T checkNotNull(T obj) {
+    if (obj == null) {
+      throw new NullPointerException();
+    }
+    return obj;
+  }
+
+  /**
+   * Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
+   */
+  static <T> T checkNotNull(T obj, String message) {
+    if (obj == null) {
+      throw new NullPointerException(message);
+    }
+    return obj;
+  }
 
   /**
    * Helper called by generated code to construct default values for string
@@ -391,9 +414,8 @@
     }
   }
 
-  /**
-   * An empty byte array constant used in generated code.
-   */
+
+  /** An empty byte array constant used in generated code. */
   public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
   /**
@@ -406,6 +428,12 @@
   public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
       CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
 
+
+  /** Helper method to merge two MessageLite instances. */
+  static Object mergeMessage(Object destination, Object source) {
+    return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
+  }
+
   /**
    * Provides an immutable view of {@code List<T>} around a {@code List<F>}.
    *
@@ -454,10 +482,13 @@
     public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
         final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
       return new Converter<Integer, T>() {
+        @Override
         public T doForward(Integer value) {
           T result = enumMap.findValueByNumber(value);
           return result == null ? unrecognizedValue : result;
         }
+
+        @Override
         public Integer doBackward(T value) {
           return value.getNumber();
         }
@@ -570,8 +601,10 @@
   /**
    * Extends {@link List} to add the capability to make the list immutable and inspect if it is
    * modifiable.
+   * <p>
+   * All implementations must support efficient random access.
    */
-  public static interface ProtobufList<E> extends List<E> {
+  public static interface ProtobufList<E> extends List<E>, RandomAccess {
 
     /**
      * Makes this list immutable. All subsequent modifications will throw an
@@ -583,6 +616,11 @@
      * Returns whether this list can be modified via the publicly accessible {@link List} methods.
      */
     boolean isModifiable();
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    ProtobufList<E> mutableCopyWithCapacity(int capacity);
   }
 
   /**
@@ -605,6 +643,12 @@
      * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     int setInt(int index, int element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    IntList mutableCopyWithCapacity(int capacity);
   }
 
   /**
@@ -627,6 +671,12 @@
      * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     boolean setBoolean(int index, boolean element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    BooleanList mutableCopyWithCapacity(int capacity);
   }
 
   /**
@@ -649,6 +699,12 @@
      * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     long setLong(int index, long element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    LongList mutableCopyWithCapacity(int capacity);
   }
 
   /**
@@ -671,6 +727,12 @@
      * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     double setDouble(int index, double element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    DoubleList mutableCopyWithCapacity(int capacity);
   }
 
   /**
@@ -693,5 +755,11 @@
      * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     float setFloat(int index, float element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    FloatList mutableCopyWithCapacity(int capacity);
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
index 85ce7b2..510c6aa 100644
--- a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -50,6 +50,10 @@
     super(e.getMessage(), e);
   }
 
+  public InvalidProtocolBufferException(final String description, IOException e) {
+    super(description, e);
+  }
+
   /**
    * Attaches an unfinished message to the exception to support best-effort
    * parsing in {@code Parser} interface.
@@ -107,11 +111,23 @@
       "Protocol message end-group tag did not match expected tag.");
   }
 
-  static InvalidProtocolBufferException invalidWireType() {
-    return new InvalidProtocolBufferException(
+  static InvalidWireTypeException invalidWireType() {
+    return new InvalidWireTypeException(
       "Protocol message tag had invalid wire type.");
   }
 
+  /**
+   * Exception indicating that and unexpected wire type was encountered for a field.
+   */
+  @ExperimentalApi
+  public static class InvalidWireTypeException extends InvalidProtocolBufferException {
+    private static final long serialVersionUID = 3283890091615336259L;
+
+    public InvalidWireTypeException(String description) {
+      super(description);
+    }
+  }
+
   static InvalidProtocolBufferException recursionLimitExceeded() {
     return new InvalidProtocolBufferException(
       "Protocol message had too many levels of nesting.  May be malicious.  " +
diff --git a/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
new file mode 100644
index 0000000..713e806
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
@@ -0,0 +1,150 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+class IterableByteBufferInputStream extends InputStream {
+  /** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */
+  private Iterator<ByteBuffer> iterator;
+  /** The current ByteBuffer; */
+  private ByteBuffer currentByteBuffer;
+  /** The number of ByteBuffers in the input data. */
+  private int dataSize;
+  /**
+   * Current {@code ByteBuffer}'s index
+   *
+   * <p>If index equals dataSize, then all the data in the InputStream has been consumed
+   */
+  private int currentIndex;
+  /** The current position for current ByteBuffer */
+  private int currentByteBufferPos;
+  /** Whether current ByteBuffer has an array */
+  private boolean hasArray;
+  /**
+   * If the current ByteBuffer is unsafe-direct based, currentArray is null; otherwise should be the
+   * array inside ByteBuffer.
+   */
+  private byte[] currentArray;
+  /** Current ByteBuffer's array offset */
+  private int currentArrayOffset;
+  /**
+   * If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this
+   * ByteBuffer; otherwise should be zero.
+   */
+  private long currentAddress;
+
+  IterableByteBufferInputStream(Iterable<ByteBuffer> data) {
+    iterator = data.iterator();
+    dataSize = 0;
+    for (ByteBuffer unused : data) {
+      dataSize++;
+    }
+    currentIndex = -1;
+
+    if (!getNextByteBuffer()) {
+      currentByteBuffer = EMPTY_BYTE_BUFFER;
+      currentIndex = 0;
+      currentByteBufferPos = 0;
+      currentAddress = 0;
+    }
+  }
+
+  private boolean getNextByteBuffer() {
+    currentIndex++;
+    if (!iterator.hasNext()) {
+      return false;
+    }
+    currentByteBuffer = iterator.next();
+    currentByteBufferPos = currentByteBuffer.position();
+    if (currentByteBuffer.hasArray()) {
+      hasArray = true;
+      currentArray = currentByteBuffer.array();
+      currentArrayOffset = currentByteBuffer.arrayOffset();
+    } else {
+      hasArray = false;
+      currentAddress = UnsafeUtil.addressOffset(currentByteBuffer);
+      currentArray = null;
+    }
+    return true;
+  }
+
+  private void updateCurrentByteBufferPos(int numberOfBytesRead) {
+    currentByteBufferPos += numberOfBytesRead;
+    if (currentByteBufferPos == currentByteBuffer.limit()) {
+      getNextByteBuffer();
+    }
+  }
+
+  @Override
+  public int read() throws IOException {
+    if (currentIndex == dataSize) {
+      return -1;
+    }
+    if (hasArray) {
+      int result = currentArray[currentByteBufferPos + currentArrayOffset] & 0xFF;
+      updateCurrentByteBufferPos(1);
+      return result;
+    } else {
+      int result = UnsafeUtil.getByte(currentByteBufferPos + currentAddress) & 0xFF;
+      updateCurrentByteBufferPos(1);
+      return result;
+    }
+  }
+
+  @Override
+  public int read(byte[] output, int offset, int length) throws IOException {
+    if (currentIndex == dataSize) {
+      return -1;
+    }
+    int remaining = currentByteBuffer.limit() - currentByteBufferPos;
+    if (length > remaining) {
+      length = remaining;
+    }
+    if (hasArray) {
+      System.arraycopy(
+          currentArray, currentByteBufferPos + currentArrayOffset, output, offset, length);
+      updateCurrentByteBufferPos(length);
+    } else {
+      int prevPos = currentByteBuffer.position();
+      currentByteBuffer.position(currentByteBufferPos);
+      currentByteBuffer.get(output, offset, length);
+      currentByteBuffer.position(prevPos);
+      updateCurrentByteBufferPos(length);
+    }
+    return length;
+  }
+}
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 5e0a485..98e13ca 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyField.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyField.java
@@ -39,14 +39,14 @@
  *
  * Most of key methods are implemented in {@link LazyFieldLite} but this class
  * can contain default instance of the message to provide {@code hashCode()},
- * {@code equals()} and {@code toString()}.
+ * {@code euqals()} and {@code toString()}.
  *
  * @author xiangl@google.com (Xiang Li)
  */
 public class LazyField extends LazyFieldLite {
 
   /**
-   * Carry a message's default instance which is used by {@code hashCode()}, {@code equals()} and
+   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
    * {@code toString()}.
    */
   private final MessageLite defaultInstance;
@@ -95,12 +95,12 @@
       this.entry = entry;
     }
 
-    // @Override
+    @Override
     public K getKey() {
       return entry.getKey();
     }
 
-    // @Override
+    @Override
     public Object getValue() {
       LazyField field = entry.getValue();
       if (field == null) {
@@ -113,7 +113,7 @@
       return entry.getValue();
     }
 
-    // @Override
+    @Override
     public Object setValue(Object value) {
       if (!(value instanceof MessageLite)) {
         throw new IllegalArgumentException(
@@ -131,13 +131,13 @@
       this.iterator = iterator;
     }
 
-    // @Override
+    @Override
     public boolean hasNext() {
       return iterator.hasNext();
     }
 
+    @Override
     @SuppressWarnings("unchecked")
-    // @Override
     public Entry<K, Object> next() {
       Entry<K, ?> entry = iterator.next();
       if (entry.getValue() instanceof LazyField) {
@@ -146,7 +146,7 @@
       return (Entry<K, Object>) entry;
     }
 
-    // @Override
+    @Override
     public void remove() {
       iterator.remove();
     }
diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
index eea1fe3..49ecfc0 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -30,14 +30,26 @@
 
 package com.google.protobuf;
 
+import java.io.IOException;
+
 /**
  * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
- * the message in a ByteString initially and then parse it on-demand.
+ * the message in a ByteString initially and then parses it on-demand.
  *
- * LazyField is thread-compatible e.g. concurrent read are safe, however,
- * synchronizations are needed under read/write situations.
+ * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
+ * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit
+ * synchronization is needed under read/write situations.
  *
- * This class is internal implementation detail, so you don't need to use it directly.
+ * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered
+ * to be immutable and none of the setter methods in its API are expected to be invoked. All of the
+ * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder,
+ * setters can be invoked, but there is no guarantee of thread safety.
+ * 
+ * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
+ * into a separate builder class to allow us to give stronger compile-time guarantees.
+ *
+ * This class is internal implementation detail of the protobuf library, so you don't need to use it
+ * directly.
  *
  * @author xiangl@google.com (Xiang Li)
  */
@@ -46,8 +58,34 @@
       ExtensionRegistryLite.getEmptyRegistry();
 
   /**
-   * A delayed-parsed version of the bytes. When this is non-null then {@code extensionRegistry } is
-   * also non-null and {@code value} and {@code memoizedBytes} are null.
+   * The value associated with the LazyFieldLite object is stored in one or more of the following
+   * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as
+   * follows.
+   * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
+   *    this state while the value for the object has not yet been parsed.
+   * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
+   *    some caller needs to access the value (by invoking getValue()).
+   * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
+   *    recomputing the ByteString representation on each call. Instead, when the value is parsed
+   *    from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since
+   *    that is the ByteString representation of value).
+   * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
+   *    delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
+   *    LazyFieldLite.toByteString().
+   *
+   * Given the above conditions, any caller that needs a serialized representation of this object
+   * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it
+   * directly; if both of those are null, it can look at the parsed value field. Similarly, any
+   * caller that needs a parsed value must first check if the value field is already non-null, if
+   * not it must parse the value from delayedBytes.
+   */
+
+  /**
+   * A delayed-parsed version of the contents of this field. When this field is non-null, then the
+   * "value" field is allowed to be null until the time that the value needs to be read.
+   *
+   * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null.
+   * {@code value} and {@code memoizedBytes} will be initialized lazily.
    */
   private ByteString delayedBytes;
 
@@ -60,12 +98,15 @@
   private ExtensionRegistryLite extensionRegistry;
 
   /**
-   * The parsed value. When this is non-null then {@code delayedBytes} will be null.
+   * The parsed value. When this is null and a caller needs access to the MessageLite value, then
+   * {@code delayedBytes} will be parsed lazily at that time.
    */
   protected volatile MessageLite value;
 
   /**
-   * The memoized bytes for {@code value}. Will be null when {@code value} is null.
+   * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to
+   * not have to recompute its return-value on each invocation.
+   * TODO(yatin): Figure out whether this optimization is actually necessary.
    */
   private volatile ByteString memoizedBytes;
 
@@ -94,6 +135,43 @@
     return lf;
   }
 
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    
+    if (!(o instanceof LazyFieldLite)) {
+      return false;
+    }
+
+    LazyFieldLite other = (LazyFieldLite) o;
+    
+    // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a
+    // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an
+    // actual message (if necessary) and call equals on the message itself. This implies that two
+    // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field.
+    MessageLite value1 = value;
+    MessageLite value2 = other.value;
+    if (value1 == null && value2 == null) {
+      return toByteString().equals(other.toByteString());
+    } else if (value1 != null && value2 != null) {
+      return value1.equals(value2);
+    } else if (value1 != null) {
+      return value1.equals(other.getValue(value1.getDefaultInstanceForType()));
+    } else {
+      return getValue(value2.getDefaultInstanceForType()).equals(value2);
+    }
+  }
+  
+  @Override
+  public int hashCode() {
+    // We can't provide a memoizable hash code for lazy fields. The byte strings may have different
+    // hash codes but evaluate to equivalent messages. And we have no facility for constructing
+    // a message here if we were not already holding a value.
+    return 1;
+  }
+  
   /**
    * Determines whether this LazyFieldLite instance represents the default instance of this type.
    */
@@ -206,28 +284,47 @@
       return;
     }
 
-    // At this point we have two fully parsed messages. We can't merge directly from one to the
-    // other because only generated builder code contains methods to mergeFrom another parsed
-    // message. We have to serialize one instance and then merge the bytes into the other. This may
-    // drop extensions from one of the messages if one of the values had an extension set on it
-    // directly.
-    //
-    // To mitigate this we prefer serializing a message that has an extension registry, and
-    // therefore a chance that all extensions set on it are in that registry.
-    //
-    // NOTE: The check for other.extensionRegistry not being null must come first because at this
-    // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be
-    // null either.
-    if (other.extensionRegistry != null) {
-      setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry));
+    // At this point we have two fully parsed messages.
+    setValue(this.value.toBuilder().mergeFrom(other.value).build());
+  }
+  
+  /**
+   * Merges another instance's contents from a stream.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    if (this.containsDefaultInstance()) {
+      setByteString(input.readBytes(), extensionRegistry);
       return;
-    } else if (this.extensionRegistry != null) {
-      setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry));
+    }
+
+    // If the other field has an extension registry but this does not, copy over the other extension
+    // registry.
+    if (this.extensionRegistry == null) {
+      this.extensionRegistry = extensionRegistry;
+    }
+
+    // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+    // the (probably rare) case that they have different extension registries there is a chance that
+    // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+    // to outway the benefits of combining the extension registries, which is not normally done for
+    // lite protos anyways.
+    if (this.delayedBytes != null) {
+      setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry);
       return;
-    } else {
-      // All extensions from the other message will be dropped because we have no registry.
-      setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
-      return;
+    }
+
+    // We are parsed and both contain data. We won't drop any extensions here directly, but in the
+    // case that the extension registries are not the same then we might in the future if we
+    // need to serialize and parse a message again.
+    try {
+      setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build());
+    } catch (InvalidProtocolBufferException e) {
+      // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+      // was invalid.
     }
   }
 
@@ -259,10 +356,12 @@
    * parsed. Be careful when using this method.
    */
   public int getSerializedSize() {
-    if (delayedBytes != null) {
-      return delayedBytes.size();
-    } else if (memoizedBytes != null) {
+    // We *must* return delayed bytes size if it was ever set because the dependent messages may
+    // have memoized serialized size based off of it.
+    if (memoizedBytes != null) {
       return memoizedBytes.size();
+    } else if (delayedBytes != null) {
+      return delayedBytes.size();
     } else if (value != null) {
       return value.getSerializedSize();
     } else {
@@ -274,12 +373,14 @@
    * Returns a BytesString for this field in a thread-safe way.
    */
   public ByteString toByteString() {
-    if (delayedBytes != null) {
-      return delayedBytes;
-    }
     if (memoizedBytes != null) {
       return memoizedBytes;
     }
+    // We *must* return delayed bytes if it was set because the dependent messages may have
+    // memoized serialized size based off of it.
+    if (delayedBytes != null) {
+      return delayedBytes;
+    }
     synchronized (this) {
       if (memoizedBytes != null) {
         return memoizedBytes;
@@ -293,6 +394,7 @@
     }
   }
 
+
   /**
    * Might lazily parse the bytes that were previously passed in. Is thread-safe.
    */
@@ -311,18 +413,15 @@
               .parseFrom(delayedBytes, extensionRegistry);
           this.value = parsedValue;
           this.memoizedBytes = delayedBytes;
-          this.delayedBytes = null;
         } else {
           this.value = defaultInstance;
           this.memoizedBytes = ByteString.EMPTY;
-          this.delayedBytes = null;
         }
       } catch (InvalidProtocolBufferException e) {
         // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
         // was invalid.
         this.value = defaultInstance;
         this.memoizedBytes = ByteString.EMPTY;
-        this.delayedBytes = null;
       }
     }
   }
diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
index c3be3cc..d474c51 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -30,12 +30,12 @@
 
 package com.google.protobuf;
 
-import java.util.Arrays;
-import java.util.List;
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.RandomAccess;
 
 /**
@@ -64,7 +64,7 @@
  */
 public class LazyStringArrayList extends AbstractProtobufList<String>
     implements LazyStringList, RandomAccess {
-  
+
   private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
   static {
     EMPTY_LIST.makeImmutable();
@@ -80,11 +80,11 @@
   private final List<Object> list;
 
   public LazyStringArrayList() {
-    list = new ArrayList<Object>();
+    this(DEFAULT_CAPACITY);
   }
 
   public LazyStringArrayList(int intialCapacity) {
-    list = new ArrayList<Object>(intialCapacity);
+    this(new ArrayList<Object>(intialCapacity));
   }
 
   public LazyStringArrayList(LazyStringList from) {
@@ -93,7 +93,21 @@
   }
 
   public LazyStringArrayList(List<String> from) {
-    list = new ArrayList<Object>(from);
+    this(new ArrayList<Object>(from));
+  }
+  
+  private LazyStringArrayList(ArrayList<Object> list) {
+    this.list = list;
+  }
+
+  @Override
+  public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size()) {
+      throw new IllegalArgumentException();
+    }
+    ArrayList<Object> newList = new ArrayList<Object>(capacity);
+    newList.addAll(list);
+    return new LazyStringArrayList(newList);
   }
 
   @Override
@@ -170,7 +184,7 @@
     return ret;
   }
 
-  // @Override
+  @Override
   public boolean addAllByteString(Collection<? extends ByteString> values) {
     ensureIsMutable();
     boolean ret = list.addAll(values);
@@ -178,7 +192,7 @@
     return ret;
   }
 
-  // @Override
+  @Override
   public boolean addAllByteArray(Collection<byte[]> c) {
     ensureIsMutable();
     boolean ret = list.addAll(c);
@@ -201,14 +215,14 @@
     modCount++;
   }
 
-  // @Override
+  @Override
   public void add(ByteString element) {
     ensureIsMutable();
     list.add(element);
     modCount++;
   }
   
-  // @Override
+  @Override
   public void add(byte[] element) {
     ensureIsMutable();
     list.add(element);
@@ -220,7 +234,7 @@
     return list.get(index);
   }
   
-  // @Override
+  @Override
   public ByteString getByteString(int index) {
     Object o = list.get(index);
     ByteString b = asByteString(o);
@@ -230,7 +244,7 @@
     return b;
   }
   
-  // @Override
+  @Override
   public byte[] getByteArray(int index) {
     Object o = list.get(index);
     byte[] b = asByteArray(o);
@@ -240,7 +254,7 @@
     return b;
   }
 
-  // @Override
+  @Override
   public void set(int index, ByteString s) {
     setAndReturn(index, s);
   }
@@ -250,7 +264,7 @@
     return list.set(index, s);
   }
 
-  // @Override
+  @Override
   public void set(int index, byte[] s) {
     setAndReturn(index, s);
   }
@@ -290,12 +304,12 @@
     }
   }
 
-  // @Override
+  @Override
   public List<?> getUnderlyingElements() {
     return Collections.unmodifiableList(list);
   }
 
-  // @Override
+  @Override
   public void mergeFrom(LazyStringList other) {
     ensureIsMutable();
     for (Object o : other.getUnderlyingElements()) {
@@ -349,7 +363,7 @@
     }
   }
   
-  // @Override
+  @Override
   public List<byte[]> asByteArrayList() {
     return new ByteArrayListView(this);
   }
@@ -393,12 +407,12 @@
     }
   }
 
-  // @Override
+  @Override
   public List<ByteString> asByteStringList() {
     return new ByteStringListView(this);
   }
 
-  // @Override
+  @Override
   public LazyStringList getUnmodifiableView() {
     if (isModifiable()) {
       return new UnmodifiableLazyStringList(this);
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index ebe6202..95945cb 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -30,36 +30,35 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.LongList;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.LongList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.RandomAccess;
 
 /**
  * An implementation of {@link LongList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class LongArrayList extends AbstractProtobufList<Long> implements LongList, RandomAccess {
-  
-  private static final int DEFAULT_CAPACITY = 10;
-  
+final class LongArrayList extends AbstractProtobufList<Long>
+    implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
+
   private static final LongArrayList EMPTY_LIST = new LongArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static LongArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private long[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -70,34 +69,70 @@
    * Constructs a new mutable {@code LongArrayList} with default capacity.
    */
   LongArrayList() {
-    this(DEFAULT_CAPACITY);
+    this(new long[DEFAULT_CAPACITY], 0);
   }
 
   /**
-   * Constructs a new mutable {@code LongArrayList} with the provided capacity.
+   * Constructs a new mutable {@code LongArrayList}
+   * containing the same elements as {@code other}.
    */
-  LongArrayList(int capacity) {
-    array = new long[capacity];
-    size = 0;
+  private LongArrayList(long[] other, int size) {
+    array = other;
+    this.size = size;
   }
 
-  /**
-   * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
-   */
-  LongArrayList(List<Long> other) {
-    if (other instanceof LongArrayList) {
-      LongArrayList list = (LongArrayList) other;
-      array = list.array.clone();
-      size = list.size;
-    } else {
-      size = other.size();
-      array = new long[size];
-      for (int i = 0; i < size; i++) {
-        array[i] = other.get(i);
+  @Override
+  protected void removeRange(int fromIndex, int toIndex) {
+    ensureIsMutable();
+    if (toIndex < fromIndex) {
+      throw new IndexOutOfBoundsException("toIndex < fromIndex");
+    }
+
+    System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
+    size -= (toIndex - fromIndex);
+    modCount++;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof LongArrayList)) {
+      return super.equals(o);
+    }
+    LongArrayList other = (LongArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+
+    final long[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
       }
     }
+
+    return true;
   }
-  
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Internal.hashLong(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public LongList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new LongArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
   @Override
   public Long get(int index) {
     return getLong(index);
@@ -149,7 +184,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -157,10 +192,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       long[] newArray = new long[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -174,38 +209,36 @@
   @Override
   public boolean addAll(Collection<? extends Long> collection) {
     ensureIsMutable();
-    
-    if (collection == null) {
-      throw new NullPointerException();
-    }
-    
+
+    checkNotNull(collection);
+
     // We specialize when adding another LongArrayList to avoid boxing elements.
     if (!(collection instanceof LongArrayList)) {
       return super.addAll(collection);
     }
-    
+
     LongArrayList list = (LongArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -225,7 +258,9 @@
     ensureIsMutable();
     ensureIndexInRange(index);
     long value = array[index];
-    System.arraycopy(array, index + 1, array, index, size - index);
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index);
+    }
     size--;
     modCount++;
     return value;
@@ -234,7 +269,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
index 31414bb..0849b82 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -33,7 +33,6 @@
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
@@ -41,63 +40,84 @@
 
 /**
  * Implements MapEntry messages.
- * 
+ *
  * In reflection API, map fields will be treated as repeated message fields and
  * each map entry is accessed as a message. This MapEntry class is used to
  * represent these map entry messages in reflection API.
- * 
+ *
  * Protobuf internal. Users shouldn't use this class.
  */
 public final class MapEntry<K, V> extends AbstractMessage {
-  private static class Metadata<K, V> {
-    public final Descriptor descriptor;  
-    public final MapEntry<K, V> defaultInstance;
-    public final AbstractParser<MapEntry<K, V>> parser;
-    
+
+  private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> {
+
+    public final Descriptor descriptor;
+    public final Parser<MapEntry<K, V>> parser;
+
     public Metadata(
-        final Descriptor descriptor, final MapEntry<K, V> defaultInstance) {
+        Descriptor descriptor,
+        MapEntry<K, V> defaultInstance,
+        WireFormat.FieldType keyType,
+        WireFormat.FieldType valueType) {
+      super(keyType, defaultInstance.key, valueType, defaultInstance.value);
       this.descriptor = descriptor;
-      this.defaultInstance = defaultInstance;
-      final Metadata<K, V> thisMetadata = this;
       this.parser = new AbstractParser<MapEntry<K, V>>() {
-        private final Parser<MapEntryLite<K, V>> dataParser =
-            defaultInstance.data.getParserForType();
+
         @Override
         public MapEntry<K, V> parsePartialFrom(
             CodedInputStream input, ExtensionRegistryLite extensionRegistry)
             throws InvalidProtocolBufferException {
-          MapEntryLite<K, V> data =
-              dataParser.parsePartialFrom(input, extensionRegistry);
-          return new MapEntry<K, V>(thisMetadata, data);
+          return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
         }
-        
       };
     }
   }
-  
+
+  private final K key;
+  private final V value;
   private final Metadata<K, V> metadata;
-  private final MapEntryLite<K, V> data;
-  
+
   /** Create a default MapEntry instance. */
-  private MapEntry(Descriptor descriptor,
+  private MapEntry(
+      Descriptor descriptor,
       WireFormat.FieldType keyType, K defaultKey,
       WireFormat.FieldType valueType, V defaultValue) {
-    this.data = MapEntryLite.newDefaultInstance(
-        keyType, defaultKey, valueType, defaultValue);
-    this.metadata = new Metadata<K, V>(descriptor, this); 
+    this.key = defaultKey;
+    this.value = defaultValue;
+    this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
   }
-  
-  /** Create a new MapEntry message. */
-  private MapEntry(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+
+  /** Create a MapEntry with the provided key and value. */
+  @SuppressWarnings("unchecked")
+  private MapEntry(Metadata metadata, K key, V value) {
+    this.key = key;
+    this.value = value;
     this.metadata = metadata;
-    this.data = data;
   }
-  
+
+  /** Parsing constructor. */
+  private MapEntry(
+      Metadata<K, V> metadata,
+      CodedInputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    try {
+      this.metadata = metadata;
+      Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry);
+      this.key = entry.getKey();
+      this.value = entry.getValue();
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this);
+    }
+  }
+
   /**
    * Create a default MapEntry instance. A default MapEntry instance should be
    * created only once for each map entry message type. Generated code should
    * store the created default instance and use it later to create new MapEntry
-   * messages of the same type. 
+   * messages of the same type.
    */
   public static <K, V> MapEntry<K, V> newDefaultInstance(
       Descriptor descriptor,
@@ -106,30 +126,38 @@
     return new MapEntry<K, V>(
         descriptor, keyType, defaultKey, valueType, defaultValue);
   }
-  
+
   public K getKey() {
-    return data.getKey();
+    return key;
   }
-  
+
   public V getValue() {
-    return data.getValue();
+    return value;
   }
-  
+
+  private volatile int cachedSerializedSize = -1;
+
   @Override
   public int getSerializedSize() {
-    return data.getSerializedSize();
+    if (cachedSerializedSize != -1) {
+      return cachedSerializedSize;
+    }
+
+    int size = MapEntryLite.computeSerializedSize(metadata, key, value);
+    cachedSerializedSize = size;
+    return size;
   }
-  
+
   @Override
   public void writeTo(CodedOutputStream output) throws IOException {
-    data.writeTo(output);
+    MapEntryLite.writeTo(output, metadata, key, value);
   }
-  
+
   @Override
   public boolean isInitialized() {
-    return data.isInitialized();
+    return isInitialized(metadata, value);
   }
-  
+
   @Override
   public Parser<MapEntry<K, V>> getParserForType() {
     return metadata.parser;
@@ -139,15 +167,15 @@
   public Builder<K, V> newBuilderForType() {
     return new Builder<K, V>(metadata);
   }
-  
+
   @Override
   public Builder<K, V> toBuilder() {
-    return new Builder<K, V>(metadata, data);
+    return new Builder<K, V>(metadata, key, value, true, true);
   }
 
   @Override
   public MapEntry<K, V> getDefaultInstanceForType() {
-    return metadata.defaultInstance;
+    return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
   }
 
   @Override
@@ -157,8 +185,7 @@
 
   @Override
   public Map<FieldDescriptor, Object> getAllFields() {
-    final TreeMap<FieldDescriptor, Object> result =
-        new TreeMap<FieldDescriptor, Object>();
+    TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
     for (final FieldDescriptor field : metadata.descriptor.getFields()) {
       if (hasField(field)) {
         result.put(field, getField(field));
@@ -166,12 +193,12 @@
     }
     return Collections.unmodifiableMap(result);
   }
-  
+
   private void checkFieldDescriptor(FieldDescriptor field) {
     if (field.getContainingType() != metadata.descriptor) {
       throw new RuntimeException(
           "Wrong FieldDescriptor \"" + field.getFullName()
-          + "\" used in message \"" + metadata.descriptor.getFullName()); 
+          + "\" used in message \"" + metadata.descriptor.getFullName());
     }
   }
 
@@ -217,56 +244,52 @@
   public static class Builder<K, V>
       extends AbstractMessage.Builder<Builder<K, V>> {
     private final Metadata<K, V> metadata;
-    private MapEntryLite<K, V> data;
-    private MapEntryLite.Builder<K, V> dataBuilder;
-    
+    private K key;
+    private V value;
+    private boolean hasKey;
+    private boolean hasValue;
+
     private Builder(Metadata<K, V> metadata) {
-      this.metadata = metadata;
-      this.data = metadata.defaultInstance.data;
-      this.dataBuilder = null;
+      this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
     }
-    
-    private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+
+    private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
       this.metadata = metadata;
-      this.data = data;
-      this.dataBuilder = null;
+      this.key = key;
+      this.value = value;
+      this.hasKey = hasKey;
+      this.hasValue = hasValue;
     }
-    
+
     public K getKey() {
-      return dataBuilder == null ? data.getKey() : dataBuilder.getKey();
+      return key;
     }
-    
+
     public V getValue() {
-      return dataBuilder == null ? data.getValue() : dataBuilder.getValue();
+      return value;
     }
-    
-    private void ensureMutable() {
-      if (dataBuilder == null) {
-        dataBuilder = data.toBuilder();
-      }
-    }
-    
+
     public Builder<K, V> setKey(K key) {
-      ensureMutable();
-      dataBuilder.setKey(key);
+      this.key = key;
+      this.hasKey = true;
       return this;
     }
-    
+
     public Builder<K, V> clearKey() {
-      ensureMutable();
-      dataBuilder.clearKey();
+      this.key = metadata.defaultKey;
+      this.hasKey = false;
       return this;
     }
-    
+
     public Builder<K, V> setValue(V value) {
-      ensureMutable();
-      dataBuilder.setValue(value);
+      this.value = value;
+      this.hasValue = true;
       return this;
     }
-    
+
     public Builder<K, V> clearValue() {
-      ensureMutable();
-      dataBuilder.clearValue();
+      this.value = metadata.defaultValue;
+      this.hasValue = false;
       return this;
     }
 
@@ -281,29 +304,24 @@
 
     @Override
     public MapEntry<K, V> buildPartial() {
-      if (dataBuilder != null) {
-        data = dataBuilder.buildPartial();
-        dataBuilder = null;
-      }
-      return new MapEntry<K, V>(metadata, data);
+      return new MapEntry<K, V>(metadata, key, value);
     }
 
     @Override
     public Descriptor getDescriptorForType() {
       return metadata.descriptor;
     }
-    
+
     private void checkFieldDescriptor(FieldDescriptor field) {
       if (field.getContainingType() != metadata.descriptor) {
         throw new RuntimeException(
             "Wrong FieldDescriptor \"" + field.getFullName()
-            + "\" used in message \"" + metadata.descriptor.getFullName()); 
+            + "\" used in message \"" + metadata.descriptor.getFullName());
       }
     }
 
     @Override
-    public com.google.protobuf.Message.Builder newBuilderForField(
-        FieldDescriptor field) {
+    public Message.Builder newBuilderForField(FieldDescriptor field) {
       checkFieldDescriptor(field);;
       // This method should be called for message fields and in a MapEntry
       // message only the value field can possibly be a message field.
@@ -312,7 +330,7 @@
         throw new RuntimeException(
             "\"" + field.getFullName() + "\" is not a message value field.");
       }
-      return ((Message) data.getValue()).newBuilderForType();
+      return ((Message) value).newBuilderForType();
     }
 
     @SuppressWarnings("unchecked")
@@ -324,6 +342,15 @@
       } else {
         if (field.getType() == FieldDescriptor.Type.ENUM) {
           value = ((EnumValueDescriptor) value).getNumber();
+        } else if (field.getType() == FieldDescriptor.Type.MESSAGE) {
+          if (value != null && !metadata.defaultValue.getClass().isInstance(value)) {
+            // The value is not the exact right message type.  However, if it
+            // is an alternative implementation of the same type -- e.g. a
+            // DynamicMessage -- we should accept it.  In this case we can make
+            // a copy of the message.
+            value =
+                ((Message) metadata.defaultValue).toBuilder().mergeFrom((Message) value).build();
+          }
         }
         setValue((V) value);
       }
@@ -362,22 +389,17 @@
 
     @Override
     public MapEntry<K, V> getDefaultInstanceForType() {
-      return metadata.defaultInstance;
+      return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
     }
 
     @Override
     public boolean isInitialized() {
-      if (dataBuilder != null) {
-        return dataBuilder.isInitialized();
-      } else {
-        return data.isInitialized();
-      }
+      return MapEntry.isInitialized(metadata, value);
     }
 
     @Override
     public Map<FieldDescriptor, Object> getAllFields() {
-      final TreeMap<FieldDescriptor, Object> result =
-          new TreeMap<FieldDescriptor, Object>();
+      final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
       for (final FieldDescriptor field : metadata.descriptor.getFields()) {
         if (hasField(field)) {
           result.put(field, getField(field));
@@ -389,7 +411,7 @@
     @Override
     public boolean hasField(FieldDescriptor field) {
       checkFieldDescriptor(field);
-      return true;
+      return field.getNumber() == 1 ? hasKey : hasValue;
     }
 
     @Override
@@ -398,8 +420,7 @@
       Object result = field.getNumber() == 1 ? getKey() : getValue();
       // Convert enums to EnumValueDescriptor.
       if (field.getType() == FieldDescriptor.Type.ENUM) {
-        result = field.getEnumType().findValueByNumberCreatingIfUnknown(
-            (java.lang.Integer) result);
+        result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result);
       }
       return result;
     }
@@ -409,25 +430,34 @@
       throw new RuntimeException(
           "There is no repeated field in a map entry message.");
     }
-    
+
     @Override
     public Object getRepeatedField(FieldDescriptor field, int index) {
       throw new RuntimeException(
           "There is no repeated field in a map entry message.");
     }
-    
+
     @Override
     public UnknownFieldSet getUnknownFields() {
       return UnknownFieldSet.getDefaultInstance();
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public Builder<K, V> clone() {
-      if (dataBuilder == null) {
-        return new Builder<K, V>(metadata, data);
-      } else {
-        return new Builder<K, V>(metadata, dataBuilder.build());
-      }
+      return new Builder(metadata, key, value, hasKey, hasValue);
     }
   }
+
+  private static <V> boolean isInitialized(Metadata metadata, V value) {
+    if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
+      return ((MessageLite) value).isInitialized();
+    }
+    return true;
+  }
+  
+  /** Returns the metadata only for experimental runtime. */
+  final Metadata<K, V> getMetadata() {
+    return metadata;
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
index bcffa94..dcb5dfa 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -31,79 +31,74 @@
 package com.google.protobuf;
 
 import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.Map;
 
 /**
  * Implements the lite version of map entry messages.
- * 
+ *
  * This class serves as an utility class to help do serialization/parsing of
  * map entries. It's used in generated code and also in the full version
  * MapEntry message.
- * 
+ *
  * Protobuf internal. Users shouldn't use.
  */
-public class MapEntryLite<K, V> extends AbstractMessageLite {
-  private static class Metadata<K, V> {
-    public final MapEntryLite<K, V> defaultInstance;
+public class MapEntryLite<K, V> {
+
+  static class Metadata<K, V> {
     public final WireFormat.FieldType keyType;
+    public final K defaultKey;
     public final WireFormat.FieldType valueType;
-    public final Parser<MapEntryLite<K, V>> parser;
+    public final V defaultValue;
+
     public Metadata(
-        MapEntryLite<K, V> defaultInstance,
-        WireFormat.FieldType keyType,
-        WireFormat.FieldType valueType) {
-      this.defaultInstance = defaultInstance; 
+        WireFormat.FieldType keyType, K defaultKey,
+        WireFormat.FieldType valueType, V defaultValue) {
       this.keyType = keyType;
+      this.defaultKey = defaultKey;
       this.valueType = valueType;
-      final Metadata<K, V> finalThis = this;
-      this.parser = new AbstractParser<MapEntryLite<K, V>>() {
-        @Override
-        public MapEntryLite<K, V> parsePartialFrom(
-            CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-            throws InvalidProtocolBufferException {
-          return new MapEntryLite<K, V>(finalThis, input, extensionRegistry);
-        }
-      };
+      this.defaultValue = defaultValue;
     }
   }
-  
+
   private static final int KEY_FIELD_NUMBER = 1;
   private static final int VALUE_FIELD_NUMBER = 2;
-  
+
   private final Metadata<K, V> metadata;
   private final K key;
   private final V value;
-  
+
   /** Creates a default MapEntryLite message instance. */
   private MapEntryLite(
       WireFormat.FieldType keyType, K defaultKey,
       WireFormat.FieldType valueType, V defaultValue) {
-    this.metadata = new Metadata<K, V>(this, keyType, valueType);
+    this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultValue);
     this.key = defaultKey;
     this.value = defaultValue;
   }
-  
+
   /** Creates a new MapEntryLite message. */
   private MapEntryLite(Metadata<K, V> metadata, K key, V value) {
     this.metadata = metadata;
     this.key = key;
     this.value = value;
   }
-  
+
   public K getKey() {
     return key;
   }
-  
+
   public V getValue() {
     return value;
   }
 
   /**
    * Creates a default MapEntryLite message instance.
-   * 
+   *
    * This method is used by generated code to create the default instance for
    * a map entry message. The created default instance should be used to create
    * new map entry messages of the same type. For each map entry message, only
-   * one default instance should be created. 
+   * one default instance should be created.
    */
   public static <K, V> MapEntryLite<K, V> newDefaultInstance(
       WireFormat.FieldType keyType, K defaultKey,
@@ -111,80 +106,20 @@
     return new MapEntryLite<K, V>(
         keyType, defaultKey, valueType, defaultValue);
   }
-  
-  @Override
-  public void writeTo(CodedOutputStream output) throws IOException {
-    writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output);
-    writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output);
+
+  static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata, K key, V value)
+      throws IOException {
+    FieldSet.writeElement(output, metadata.keyType, KEY_FIELD_NUMBER, key);
+    FieldSet.writeElement(output, metadata.valueType, VALUE_FIELD_NUMBER, value);
   }
 
-  private void writeField(
-      int number, WireFormat.FieldType type, Object value,
-      CodedOutputStream output) throws IOException {
-    output.writeTag(number, type.getWireType());
-    FieldSet.writeElementNoTag(output, type, value);
+  static <K, V> int computeSerializedSize(Metadata<K, V> metadata, K key, V value) {
+    return FieldSet.computeElementSize(metadata.keyType, KEY_FIELD_NUMBER, key)
+        + FieldSet.computeElementSize(metadata.valueType, VALUE_FIELD_NUMBER, value);
   }
 
-  private volatile int cachedSerializedSize = -1;
-  @Override
-  public int getSerializedSize() {
-    if (cachedSerializedSize != -1) {
-      return cachedSerializedSize;
-    }
-    int size = 0;
-    size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key);
-    size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value);
-    cachedSerializedSize = size;
-    return size;
-  }
-
-  private int getFieldSize(
-      int number, WireFormat.FieldType type, Object value) {
-    return CodedOutputStream.computeTagSize(number)
-        + FieldSet.computeElementSizeNoTag(type, value);
-  }
-  
-  /** Parsing constructor. */
-  private MapEntryLite(
-      Metadata<K, V> metadata,
-      CodedInputStream input,
-      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    try {
-      K key = metadata.defaultInstance.key;
-      V value = metadata.defaultInstance.value;
-      while (true) {
-        int tag = input.readTag();
-        if (tag == 0) {
-          break;
-        }
-        if (tag == WireFormat.makeTag(
-                KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
-          key = mergeField(
-              input, extensionRegistry, metadata.keyType, key);
-        } else if (tag == WireFormat.makeTag(
-                       VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
-          value = mergeField(
-              input, extensionRegistry, metadata.valueType, value);
-        } else {
-          if (!input.skipField(tag)) {
-            break;
-          }
-        }
-      }
-      this.metadata = metadata;
-      this.key = key;
-      this.value = value;
-    } catch (InvalidProtocolBufferException e) {
-      throw e.setUnfinishedMessage(this);
-    } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage())
-          .setUnfinishedMessage(this);
-    }
-  }
-  
   @SuppressWarnings("unchecked")
-  private <T> T mergeField(
+  static <T> T parseField(
       CodedInputStream input, ExtensionRegistryLite extensionRegistry,
       WireFormat.FieldType type, T value) throws IOException {
     switch (type) {
@@ -201,131 +136,96 @@
     }
   }
 
-  @Override
-  public Parser<MapEntryLite<K, V>> getParserForType() {
-    return metadata.parser;
-  }
-
-  @Override
-  public Builder<K, V> newBuilderForType() {
-    return new Builder<K, V>(metadata);
-  }
-
-  @Override
-  public Builder<K, V> toBuilder() {
-    return new Builder<K, V>(metadata, key, value);
-  }
-
-  @Override
-  public MapEntryLite<K, V> getDefaultInstanceForType() {
-    return metadata.defaultInstance;
-  }
-
-  @Override
-  public boolean isInitialized() {
-    if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
-      return ((MessageLite) value).isInitialized();
-    }
-    return true;
+  /**
+   * Serializes the provided key and value as though they were wrapped by a {@link MapEntryLite}
+   * to the output stream. This helper method avoids allocation of a {@link MapEntryLite}
+   * built with a key and value and is called from generated code directly.
+   */
+  public void serializeTo(CodedOutputStream output, int fieldNumber, K key, V value)
+      throws IOException {
+    output.writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeUInt32NoTag(computeSerializedSize(metadata, key, value));
+    writeTo(output, metadata, key, value);
   }
 
   /**
-   * Builder used to create {@link MapEntryLite} messages.
+   * Computes the message size for the provided key and value as though they were wrapped
+   * by a {@link MapEntryLite}. This helper method avoids allocation of a {@link MapEntryLite}
+   * built with a key and value and is called from generated code directly.
    */
-  public static class Builder<K, V>
-      extends AbstractMessageLite.Builder<Builder<K, V>> {
-    private final Metadata<K, V> metadata;
-    private K key;
-    private V value;
-    
-    private Builder(Metadata<K, V> metadata) {
-      this.metadata = metadata;
-      this.key = metadata.defaultInstance.key;
-      this.value = metadata.defaultInstance.value;
-    }
-    
-    public K getKey() {
-      return key;
-    }
-    
-    public V getValue() {
-      return value;
-    }
-    
-    public Builder<K, V> setKey(K key) {
-      this.key = key;
-      return this;
-    }
-    
-    public Builder<K, V> setValue(V value) {
-      this.value = value;
-      return this;
-    }
-    
-    public Builder<K, V> clearKey() {
-      this.key = metadata.defaultInstance.key;
-      return this;
-    }
-    
-    public Builder<K, V> clearValue() {
-      this.value = metadata.defaultInstance.value;
-      return this;
-    }
+  public int computeMessageSize(int fieldNumber, K key, V value) {
+    return CodedOutputStream.computeTagSize(fieldNumber)
+        + CodedOutputStream.computeLengthDelimitedFieldSize(
+            computeSerializedSize(metadata, key, value));
+  }
 
-    @Override
-    public Builder<K, V> clear() {
-      this.key = metadata.defaultInstance.key;
-      this.value = metadata.defaultInstance.value;
-      return this;
-    }
+  /**
+   * Parses an entry off of the input as a {@link Map.Entry}. This helper requires an allocation
+   * so using {@link #parseInto} is preferred if possible.
+   */
+  public Map.Entry<K, V> parseEntry(ByteString bytes, ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    return parseEntry(bytes.newCodedInput(), metadata, extensionRegistry);
+  }
 
-    @Override
-    public MapEntryLite<K, V> build() {
-      MapEntryLite<K, V> result = buildPartial();
-      if (!result.isInitialized()) {
-        throw newUninitializedMessageException(result);
+  static <K, V> Map.Entry<K, V> parseEntry(
+      CodedInputStream input, Metadata<K, V> metadata, ExtensionRegistryLite extensionRegistry)
+          throws IOException{
+    K key = metadata.defaultKey;
+    V value = metadata.defaultValue;
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
       }
-      return result;
-    }
-
-    @Override
-    public MapEntryLite<K, V> buildPartial() {
-      return new MapEntryLite<K, V>(metadata, key, value);
-    }
-
-    @Override
-    public MessageLite getDefaultInstanceForType() {
-      return metadata.defaultInstance;
-    }
-
-    @Override
-    public boolean isInitialized() {
-      if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
-        return ((MessageLite) value).isInitialized();
+      if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
+        key = parseField(input, extensionRegistry, metadata.keyType, key);
+      } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
+        value = parseField(input, extensionRegistry, metadata.valueType, value);
+      } else {
+        if (!input.skipField(tag)) {
+          break;
+        }
       }
-      return true;
+    }
+    return new AbstractMap.SimpleImmutableEntry<K, V>(key, value);
+  }
+
+  /**
+   * Parses an entry off of the input into the map. This helper avoids allocaton of a
+   * {@link MapEntryLite} by parsing directly into the provided {@link MapFieldLite}.
+   */
+  public void parseInto(
+      MapFieldLite<K, V> map, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws IOException {
+    int length = input.readRawVarint32();
+    final int oldLimit = input.pushLimit(length);
+    K key = metadata.defaultKey;
+    V value = metadata.defaultValue;
+
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+      if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
+        key = parseField(input, extensionRegistry, metadata.keyType, key);
+      } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
+        value = parseField(input, extensionRegistry, metadata.valueType, value);
+      } else {
+        if (!input.skipField(tag)) {
+          break;
+        }
+      }
     }
 
-    private Builder(Metadata<K, V> metadata, K key, V value) {
-      this.metadata = metadata;
-      this.key = key;
-      this.value = value;
-    }
-    
-    @Override
-    public Builder<K, V> clone() {
-      return new Builder<K, V>(metadata, key, value);
-    }
+    input.checkLastTagWas(0);
+    input.popLimit(oldLimit);
+    map.put(key, value);
+  }
 
-    @Override
-    public Builder<K, V> mergeFrom(
-        CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      MapEntryLite<K, V> entry =
-          new MapEntryLite<K, V>(metadata, input, extensionRegistry);
-      this.key = entry.key;
-      this.value = entry.value;
-      return this;
-    }
+  /** For experimental runtime internal use only. */
+  Metadata<K, V> getMetadata() {
+    return metadata;
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
index b290993..ad8ceb0 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -30,25 +30,28 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.MapFieldLite.MutatabilityAwareMap;
+import static com.google.protobuf.Internal.checkNotNull;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Internal representation of map fields in generated messages.
- * 
+ *
  * This class supports accessing the map field as a {@link Map} to be used in
  * generated API and also supports accessing the field as a {@link List} to be
  * used in reflection API. It keeps track of where the data is currently stored
- * and do necessary conversions between map and list.  
- * 
+ * and do necessary conversions between map and list.
+ *
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
- * 
+ *
  * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap()
  * and getList() concurrently in multiple threads. If write-access is needed,
  * all access must be synchronized.
@@ -56,21 +59,21 @@
 public class MapField<K, V> implements MutabilityOracle {
   /**
    * Indicates where the data of this map field is currently stored.
-   * 
+   *
    * MAP: Data is stored in mapData.
    * LIST: Data is stored in listData.
    * BOTH: mapData and listData have the same data.
    *
    * When the map field is accessed (through generated API or reflection API),
    * it will shift between these 3 modes:
-   * 
+   *
    *          getMap()   getList()   getMutableMap()   getMutableList()
    *   MAP      MAP        BOTH          MAP               LIST
    *   LIST     BOTH       LIST          MAP               LIST
    *   BOTH     BOTH       BOTH          MAP               LIST
-   *   
+   *
    * As the map field changes its mode, the list/map reference returned in a
-   * previous method call may be invalidated. 
+   * previous method call may be invalidated.
    */
   private enum StorageMode {MAP, LIST, BOTH}
 
@@ -78,38 +81,42 @@
   private volatile StorageMode mode;
   private MutatabilityAwareMap<K, V> mapData;
   private List<Message> listData;
-  
+
   // Convert between a map entry Message and a key-value pair.
   private static interface Converter<K, V> {
     Message convertKeyAndValueToMessage(K key, V value);
     void convertMessageToKeyAndValue(Message message, Map<K, V> map);
-    
+
     Message getMessageDefaultInstance();
   }
-  
+
   private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
     private final MapEntry<K, V> defaultEntry;
     public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
       this.defaultEntry = defaultEntry;
     }
-    
+
+    @Override
     public Message convertKeyAndValueToMessage(K key, V value) {
       return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
     }
-    
+
+    @Override
+    @SuppressWarnings("unchecked")
     public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
       MapEntry<K, V> entry = (MapEntry<K, V>) message;
       map.put(entry.getKey(), entry.getValue());
     }
 
+    @Override
     public Message getMessageDefaultInstance() {
       return defaultEntry;
     }
   }
-  
+
 
   private final Converter<K, V> converter;
-  
+
   private MapField(
       Converter<K, V> converter,
       StorageMode mode,
@@ -120,34 +127,34 @@
     this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
     this.listData = null;
   }
-    
+
   private MapField(
       MapEntry<K, V> defaultEntry,
       StorageMode mode,
       Map<K, V> mapData) {
     this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
   }
-  
-  
+
+
   /** Returns an immutable empty MapField. */
   public static <K, V> MapField<K, V> emptyMapField(
       MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
         defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
   }
-  
-  
+
+
   /** Creates a new mutable empty MapField. */
   public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
         defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
   }
-  
-  
+
+
   private Message convertKeyAndValueToMessage(K key, V value) {
     return converter.convertKeyAndValueToMessage(key, value);
   }
-  
+
   @SuppressWarnings("unchecked")
   private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
     converter.convertMessageToKeyAndValue(message, map);
@@ -170,7 +177,7 @@
     }
     return new MutatabilityAwareMap<K, V>(this, mapData);
   }
-  
+
   /** Returns the content of this MapField as a read-only Map. */
   public Map<K, V> getMap() {
     if (mode == StorageMode.LIST) {
@@ -183,7 +190,7 @@
     }
     return Collections.unmodifiableMap(mapData);
   }
-  
+
   /** Gets a mutable Map view of this MapField. */
   public Map<K, V> getMutableMap() {
     if (mode != StorageMode.MAP) {
@@ -191,20 +198,20 @@
         mapData = convertListToMap(listData);
       }
       listData = null;
-      mode = StorageMode.MAP; 
+      mode = StorageMode.MAP;
     }
     return mapData;
   }
-  
+
   public void mergeFrom(MapField<K, V> other) {
     getMutableMap().putAll(MapFieldLite.copy(other.getMap()));
   }
-  
+
   public void clear() {
     mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
     mode = StorageMode.MAP;
   }
-  
+
   @SuppressWarnings("unchecked")
   @Override
   public boolean equals(Object object) {
@@ -214,18 +221,18 @@
     MapField<K, V> other = (MapField<K, V>) object;
     return MapFieldLite.<K, V>equals(getMap(), other.getMap());
   }
-  
+
   @Override
   public int hashCode() {
     return MapFieldLite.<K, V>calculateHashCodeForMap(getMap());
   }
-  
+
   /** Returns a deep copy of this MapField. */
   public MapField<K, V> copy() {
     return new MapField<K, V>(
         converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
   }
-  
+
   /** Gets the content of this MapField as a read-only List. */
   List<Message> getList() {
     if (mode == StorageMode.MAP) {
@@ -238,7 +245,7 @@
     }
     return Collections.unmodifiableList(listData);
   }
-  
+
   /** Gets a mutable List view of this MapField. */
   List<Message> getMutableList() {
     if (mode != StorageMode.LIST) {
@@ -250,7 +257,7 @@
     }
     return listData;
   }
-  
+
   /**
    * Gets the default instance of the message stored in the list view of this
    * map field.
@@ -258,7 +265,7 @@
   Message getMapEntryMessageDefaultInstance() {
     return converter.getMessageDefaultInstance();
   }
-  
+
   /**
    * Makes this list immutable. All subsequent modifications will throw an
    * {@link UnsupportedOperationException}.
@@ -266,14 +273,14 @@
   public void makeImmutable() {
     isMutable = false;
   }
-  
+
   /**
    * Returns whether this field can be modified.
    */
   public boolean isMutable() {
     return isMutable;
   }
-  
+
   /* (non-Javadoc)
    * @see com.google.protobuf.MutabilityOracle#ensureMutable()
    */
@@ -283,4 +290,344 @@
       throw new UnsupportedOperationException();
     }
   }
+
+  /**
+   * An internal map that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareMap<K, V> implements Map<K, V> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Map<K, V> delegate;
+
+    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+      return delegate.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+      return delegate.containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+      return delegate.get(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      mutabilityOracle.ensureMutable();
+      checkNotNull(key);
+      checkNotNull(value);
+      return delegate.put(key, value);
+    }
+
+    @Override
+    public V remove(Object key) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+      mutabilityOracle.ensureMutable();
+      for (K key : m.keySet()) {
+        checkNotNull(key);
+        checkNotNull(m.get(key));
+      }
+      delegate.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+
+    /**
+     * An internal collection that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareCollection<E> implements Collection<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Collection<E> delegate;
+
+      MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public int size() {
+        return delegate.size();
+      }
+
+      @Override
+      public boolean isEmpty() {
+        return delegate.isEmpty();
+      }
+
+      @Override
+      public boolean contains(Object o) {
+        return delegate.contains(o);
+      }
+
+      @Override
+      public Iterator<E> iterator() {
+        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+      }
+
+      @Override
+      public Object[] toArray() {
+        return delegate.toArray();
+      }
+
+      @Override
+      public <T> T[] toArray(T[] a) {
+        return delegate.toArray(a);
+      }
+
+      @Override
+      public boolean add(E e) {
+        // Unsupported operation in the delegate.
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public boolean remove(Object o) {
+        mutabilityOracle.ensureMutable();
+        return delegate.remove(o);
+      }
+
+      @Override
+      public boolean containsAll(Collection<?> c) {
+        return delegate.containsAll(c);
+      }
+
+      @Override
+      public boolean addAll(Collection<? extends E> c) {
+        // Unsupported operation in the delegate.
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public boolean removeAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.removeAll(c);
+      }
+
+      @Override
+      public boolean retainAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.retainAll(c);
+      }
+
+      @Override
+      public void clear() {
+        mutabilityOracle.ensureMutable();
+        delegate.clear();
+      }
+
+      @Override
+      public boolean equals(Object o) {
+        return delegate.equals(o);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+
+    /**
+     * An internal set that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareSet<E> implements Set<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Set<E> delegate;
+
+      MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public int size() {
+        return delegate.size();
+      }
+
+      @Override
+      public boolean isEmpty() {
+        return delegate.isEmpty();
+      }
+
+      @Override
+      public boolean contains(Object o) {
+        return delegate.contains(o);
+      }
+
+      @Override
+      public Iterator<E> iterator() {
+        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+      }
+
+      @Override
+      public Object[] toArray() {
+        return delegate.toArray();
+      }
+
+      @Override
+      public <T> T[] toArray(T[] a) {
+        return delegate.toArray(a);
+      }
+
+      @Override
+      public boolean add(E e) {
+        mutabilityOracle.ensureMutable();
+        return delegate.add(e);
+      }
+
+      @Override
+      public boolean remove(Object o) {
+        mutabilityOracle.ensureMutable();
+        return delegate.remove(o);
+      }
+
+      @Override
+      public boolean containsAll(Collection<?> c) {
+        return delegate.containsAll(c);
+      }
+
+      @Override
+      public boolean addAll(Collection<? extends E> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.addAll(c);
+      }
+
+      @Override
+      public boolean retainAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.retainAll(c);
+      }
+
+      @Override
+      public boolean removeAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.removeAll(c);
+      }
+
+      @Override
+      public void clear() {
+        mutabilityOracle.ensureMutable();
+        delegate.clear();
+      }
+
+      @Override
+      public boolean equals(Object o) {
+        return delegate.equals(o);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+
+    /**
+     * An internal iterator that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareIterator<E> implements Iterator<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Iterator<E> delegate;
+
+      MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public boolean hasNext() {
+        return delegate.hasNext();
+      }
+
+      @Override
+      public E next() {
+        return delegate.next();
+      }
+
+      @Override
+      public void remove() {
+        mutabilityOracle.ensureMutable();
+        delegate.remove();
+      }
+
+      @Override
+      public boolean equals(Object obj) {
+        return delegate.equals(obj);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index 960b633..a8b3dd8 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -30,74 +30,100 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.Internal.EnumLite;
+import static com.google.protobuf.Internal.checkNotNull;
 
+import com.google.protobuf.Internal.EnumLite;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Internal representation of map fields in generated lite-runtime messages.
- * 
+ *
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
  */
-public final class MapFieldLite<K, V> implements MutabilityOracle {
-  private MutatabilityAwareMap<K, V> mapData;
+public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
+
   private boolean isMutable;
-  
-  private MapFieldLite(Map<K, V> mapData) {
-    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+
+  private MapFieldLite() {
     this.isMutable = true;
   }
-  
+
+  private MapFieldLite(Map<K, V> mapData) {
+    super(mapData);
+    this.isMutable = true;
+  }
+
   @SuppressWarnings({"rawtypes", "unchecked"})
-  private static final MapFieldLite EMPTY_MAP_FIELD =
-      new MapFieldLite(Collections.emptyMap());
+  private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite();
   static {
     EMPTY_MAP_FIELD.makeImmutable();
   }
-  
+
   /** Returns an singleton immutable empty MapFieldLite instance. */
   @SuppressWarnings({"unchecked", "cast"})
   public static <K, V> MapFieldLite<K, V> emptyMapField() {
     return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
   }
-  
-  /** Creates a new MapFieldLite instance. */
-  public static <K, V> MapFieldLite<K, V> newMapField() {
-    return new MapFieldLite<K, V>(new LinkedHashMap<K, V>());
-  }
-  
-  /** Gets the content of this MapField as a read-only Map. */
-  public Map<K, V> getMap() {
-    return Collections.unmodifiableMap(mapData);
-  }
-  
-  /** Gets a mutable Map view of this MapField. */
-  public Map<K, V> getMutableMap() {
-    return mapData;
-  }
-  
+
   public void mergeFrom(MapFieldLite<K, V> other) {
-    mapData.putAll(copy(other.mapData));
+    ensureMutable();
+    if (!other.isEmpty()) {
+      putAll(other);
+    }
   }
-  
-  public void clear() {
-    mapData.clear();
+
+  @SuppressWarnings({"unchecked", "cast"})
+  @Override public Set<Map.Entry<K, V>> entrySet() {
+    return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet();
   }
-  
+
+  @Override public void clear() {
+    ensureMutable();
+    super.clear();
+  }
+
+  @Override public V put(K key, V value) {
+    ensureMutable();
+    checkNotNull(key);
+
+    checkNotNull(value);
+    return super.put(key, value);
+  }
+
+  public V put(Map.Entry<K, V> entry) {
+    return put(entry.getKey(), entry.getValue());
+  }
+
+  @Override public void putAll(Map<? extends K, ? extends V> m) {
+    ensureMutable();
+    checkForNullKeysAndValues(m);
+    super.putAll(m);
+  }
+
+  @Override public V remove(Object key) {
+    ensureMutable();
+    return super.remove(key);
+  }
+
+  private static void checkForNullKeysAndValues(Map<?, ?> m) {
+    for (Object key : m.keySet()) {
+      checkNotNull(key);
+      checkNotNull(m.get(key));
+    }
+  }
+
   private static boolean equals(Object a, Object b) {
     if (a instanceof byte[] && b instanceof byte[]) {
       return Arrays.equals((byte[]) a, (byte[]) b);
     }
     return a.equals(b);
   }
-  
+
   /**
    * Checks whether two {@link Map}s are equal. We don't use the default equals
    * method of {@link Map} because it compares by identity not by content for
@@ -120,20 +146,16 @@
     }
     return true;
   }
-  
+
   /**
    * Checks whether two map fields are equal.
    */
   @SuppressWarnings("unchecked")
   @Override
   public boolean equals(Object object) {
-    if (!(object instanceof MapFieldLite)) {
-      return false;
-    }
-    MapFieldLite<K, V> other = (MapFieldLite<K, V>) object;
-    return equals(mapData, other.mapData);
+    return (object instanceof Map) && equals(this, (Map<K, V>) object);
   }
-  
+
   private static int calculateHashCodeForObject(Object a) {
     if (a instanceof byte[]) {
       return Internal.hashCode((byte[]) a);
@@ -156,14 +178,14 @@
       result += calculateHashCodeForObject(entry.getKey())
           ^ calculateHashCodeForObject(entry.getValue());
     }
-    return result;    
+    return result;
   }
-  
+
   @Override
   public int hashCode() {
-    return calculateHashCodeForMap(mapData);
+    return calculateHashCodeForMap(this);
   }
-  
+
   private static Object copy(Object object) {
     if (object instanceof byte[]) {
       byte[] data = (byte[]) object;
@@ -171,7 +193,7 @@
     }
     return object;
   }
-  
+
   /**
    * Makes a deep copy of a {@link Map}. Immutable objects in the map will be
    * shared (e.g., integers, strings, immutable messages) and mutable ones will
@@ -185,12 +207,12 @@
     }
     return result;
   }
-  
+
   /** Returns a deep copy of this map field. */
-  public MapFieldLite<K, V> copy() {
-    return new MapFieldLite<K, V>(copy(mapData));
+  public MapFieldLite<K, V> mutableCopy() {
+    return isEmpty() ? new MapFieldLite<K, V>() : new MapFieldLite<K, V>(this);
   }
-  
+
   /**
    * Makes this field immutable. All subsequent modifications will throw an
    * {@link UnsupportedOperationException}.
@@ -198,352 +220,17 @@
   public void makeImmutable() {
     isMutable = false;
   }
-  
+
   /**
    * Returns whether this field can be modified.
    */
   public boolean isMutable() {
     return isMutable;
   }
-  
-  @Override
-  public void ensureMutable() {
+
+  private void ensureMutable() {
     if (!isMutable()) {
       throw new UnsupportedOperationException();
     }
   }
-
-  /**
-   * An internal map that checks for mutability before delegating.
-   */
-  static class MutatabilityAwareMap<K, V> implements Map<K, V> {    
-    private final MutabilityOracle mutabilityOracle;
-    private final Map<K, V> delegate;
-    
-    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean containsKey(Object key) {
-      return delegate.containsKey(key);
-    }
-
-    @Override
-    public boolean containsValue(Object value) {
-      return delegate.containsValue(value);
-    }
-
-    @Override
-    public V get(Object key) {
-      return delegate.get(key);
-    }
-
-    @Override
-    public V put(K key, V value) {
-      mutabilityOracle.ensureMutable();
-      return delegate.put(key, value);
-    }
-
-    @Override
-    public V remove(Object key) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(key);
-    }
-
-    @Override
-    public void putAll(Map<? extends K, ? extends V> m) {
-      mutabilityOracle.ensureMutable();
-      delegate.putAll(m);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public Set<K> keySet() {
-      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
-    }
-
-    @Override
-    public Collection<V> values() {
-      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
-    }
-
-    @Override
-    public Set<java.util.Map.Entry<K, V>> entrySet() {
-      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-
-  /**
-   * An internal collection that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareCollection<E> implements Collection<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Collection<E> delegate;
-    
-    MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-      return delegate.contains(o);
-    }
-
-    @Override
-    public Iterator<E> iterator() {
-      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
-    }
-
-    @Override
-    public Object[] toArray() {
-      return delegate.toArray();
-    }
-
-    @Override
-    public <T> T[] toArray(T[] a) {
-      return delegate.toArray(a);
-    }
-
-    @Override
-    public boolean add(E e) {
-      // Unsupported operation in the delegate.
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(o);
-    }
-
-    @Override
-    public boolean containsAll(Collection<?> c) {
-      return delegate.containsAll(c);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends E> c) {
-      // Unsupported operation in the delegate.
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.retainAll(c);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-    
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-
-  /**
-   * An internal set that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareSet<E> implements Set<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Set<E> delegate;
-    
-    MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-      return delegate.contains(o);
-    }
-
-    @Override
-    public Iterator<E> iterator() {
-      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
-    }
-
-    @Override
-    public Object[] toArray() {
-      return delegate.toArray();
-    }
-
-    @Override
-    public <T> T[] toArray(T[] a) {
-      return delegate.toArray(a);
-    }
-
-    @Override
-    public boolean add(E e) {
-      mutabilityOracle.ensureMutable();
-      return delegate.add(e);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(o);
-    }
-
-    @Override
-    public boolean containsAll(Collection<?> c) {
-      return delegate.containsAll(c);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends E> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.addAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.retainAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.removeAll(c);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-  
-  /**
-   * An internal iterator that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareIterator<E> implements Iterator<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Iterator<E> delegate;
-    
-    MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public boolean hasNext() {
-      return delegate.hasNext();
-    }
-
-    @Override
-    public E next() {
-      return delegate.next();
-    }
-
-    @Override
-    public void remove() {
-      mutabilityOracle.ensureMutable();
-      delegate.remove();
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-      return delegate.equals(obj);
-    }
-    
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
index 9516d71..0770d41 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -51,6 +51,7 @@
 public interface Message extends MessageLite, MessageOrBuilder {
 
   // (From MessageLite, re-declared here only for return type covariance.)
+  @Override
   Parser<? extends Message> getParserForType();
 
 
@@ -97,7 +98,10 @@
   // Builders
 
   // (From MessageLite, re-declared here only for return type covariance.)
+  @Override
   Builder newBuilderForType();
+
+  @Override
   Builder toBuilder();
 
   /**
@@ -106,6 +110,7 @@
   interface Builder extends MessageLite.Builder, MessageOrBuilder {
     // (From MessageLite.Builder, re-declared here only for return type
     // covariance.)
+    @Override
     Builder clear();
 
     /**
@@ -120,7 +125,7 @@
      *   it is merged into the corresponding sub-message of this message
      *   using the same merging rules.<br>
      * * For repeated fields, the elements in {@code other} are concatenated
-     *   with the elements in this message.
+     *   with the elements in this message.<br>
      * * For oneof groups, if the other message has one of the fields set,
      *   the group of this message is cleared and replaced by the field
      *   of the other message, so that the oneof constraint is preserved.
@@ -131,18 +136,27 @@
 
     // (From MessageLite.Builder, re-declared here only for return type
     // covariance.)
+    @Override
     Message build();
+
+    @Override
     Message buildPartial();
+
+    @Override
     Builder clone();
+
+    @Override
     Builder mergeFrom(CodedInputStream input) throws IOException;
-    Builder mergeFrom(CodedInputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
+
+    @Override
+    Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
 
     /**
      * Get the message's type's descriptor.
      * See {@link Message#getDescriptorForType()}.
      */
+    @Override
     Descriptors.Descriptor getDescriptorForType();
 
     /**
@@ -240,27 +254,39 @@
 
     // (From MessageLite.Builder, re-declared here only for return type
     // covariance.)
+    @Override
     Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
-    Builder mergeFrom(ByteString data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
     Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data, int off, int len)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data, int off, int len,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
     Builder mergeFrom(InputStream input) throws IOException;
-    Builder mergeFrom(InputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
-    boolean mergeDelimitedFrom(InputStream input)
-                               throws IOException;
-    boolean mergeDelimitedFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-                               throws IOException;
+
+    @Override
+    Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+
+    @Override
+    boolean mergeDelimitedFrom(InputStream input) throws IOException;
+
+    @Override
+    boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java
index 798b794..88f531d 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLite.java
@@ -295,6 +295,27 @@
     Builder mergeFrom(InputStream input,
                       ExtensionRegistryLite extensionRegistry)
                       throws IOException;
+    
+    /**
+     * Merge {@code other} into the message being built.  {@code other} must
+     * have the exact same type as {@code this} (i.e.
+     * {@code getClass().equals(getDefaultInstanceForType().getClass())}).
+     *
+     * Merging occurs as follows.  For each field:<br>
+     * * For singular primitive fields, if the field is set in {@code other},
+     *   then {@code other}'s value overwrites the value in this message.<br>
+     * * For singular message fields, if the field is set in {@code other},
+     *   it is merged into the corresponding sub-message of this message
+     *   using the same merging rules.<br>
+     * * For repeated fields, the elements in {@code other} are concatenated
+     *   with the elements in this message.
+     * * For oneof groups, if the other message has one of the fields set,
+     *   the group of this message is cleared and replaced by the field
+     *   of the other message, so that the oneof constraint is preserved.
+     *
+     * This is equivalent to the {@code Message::MergeFrom} method in C++.
+     */
+    Builder mergeFrom(MessageLite other);
 
     /**
      * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
index e69de29..8e26593 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
@@ -0,0 +1,281 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/** Helps generate {@link String} representations of {@link MessageLite} protos. */
+final class MessageLiteToString {
+
+  private static final String LIST_SUFFIX = "List";
+  private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
+  private static final String MAP_SUFFIX = "Map";
+  private static final String BYTES_SUFFIX = "Bytes";
+
+  /**
+   * Returns a {@link String} representation of the {@link MessageLite} object. The first line of
+   * the {@code String} representation representation includes a comment string to uniquely identify
+   * the object instance. This acts as an indicator that this should not be relied on for
+   * comparisons.
+   *
+   * <p>For use by generated code only.
+   */
+  static String toString(MessageLite messageLite, String commentString) {
+    StringBuilder buffer = new StringBuilder();
+    buffer.append("# ").append(commentString);
+    reflectivePrintWithIndent(messageLite, buffer, 0);
+    return buffer.toString();
+  }
+
+  /**
+   * Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces to indent the proto by
+   */
+  private static void reflectivePrintWithIndent(
+      MessageLite messageLite, StringBuilder buffer, int indent) {
+    // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
+    // getFooList() and getFooMap() which might be useful for building an object's string
+    // representation.
+    Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
+    Map<String, Method> nameToMethod = new HashMap<String, Method>();
+    Set<String> getters = new TreeSet<String>();
+    for (Method method : messageLite.getClass().getDeclaredMethods()) {
+      nameToMethod.put(method.getName(), method);
+      if (method.getParameterTypes().length == 0) {
+        nameToNoArgMethod.put(method.getName(), method);
+
+        if (method.getName().startsWith("get")) {
+          getters.add(method.getName());
+        }
+      }
+    }
+
+    for (String getter : getters) {
+      String suffix = getter.replaceFirst("get", "");
+      if (suffix.endsWith(LIST_SUFFIX)
+          && !suffix.endsWith(BUILDER_LIST_SUFFIX)
+          // Sometimes people have fields named 'list' that aren't repeated.
+          && !suffix.equals(LIST_SUFFIX)) {
+        String camelCase =
+            suffix.substring(0, 1).toLowerCase()
+                + suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
+        // Try to reflectively get the value and toString() the field as if it were repeated. This
+        // only works if the method names have not been proguarded out or renamed.
+        Method listMethod = nameToNoArgMethod.get(getter);
+        if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
+          printField(
+              buffer,
+              indent,
+              camelCaseToSnakeCase(camelCase),
+              GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
+          continue;
+        }
+      }
+      if (suffix.endsWith(MAP_SUFFIX)
+          // Sometimes people have fields named 'map' that aren't maps.
+          && !suffix.equals(MAP_SUFFIX)) {
+        String camelCase =
+            suffix.substring(0, 1).toLowerCase()
+                + suffix.substring(1, suffix.length() - MAP_SUFFIX.length());
+        // Try to reflectively get the value and toString() the field as if it were a map. This only
+        // works if the method names have not been proguarded out or renamed.
+        Method mapMethod = nameToNoArgMethod.get(getter);
+        if (mapMethod != null
+            && mapMethod.getReturnType().equals(Map.class)
+            // Skip the deprecated getter method with no prefix "Map" when the field name ends with
+            // "map".
+            && !mapMethod.isAnnotationPresent(Deprecated.class)
+            // Skip the internal mutable getter method.
+            && Modifier.isPublic(mapMethod.getModifiers())) {
+          printField(
+              buffer,
+              indent,
+              camelCaseToSnakeCase(camelCase),
+              GeneratedMessageLite.invokeOrDie(mapMethod, messageLite));
+          continue;
+        }
+      }
+
+      Method setter = nameToMethod.get("set" + suffix);
+      if (setter == null) {
+        continue;
+      }
+      if (suffix.endsWith(BYTES_SUFFIX)
+          && nameToNoArgMethod.containsKey(
+              "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
+        // Heuristic to skip bytes based accessors for string fields.
+        continue;
+      }
+
+      String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
+
+      // Try to reflectively get the value and toString() the field as if it were optional. This
+      // only works if the method names have not been proguarded out or renamed.
+      Method getMethod = nameToNoArgMethod.get("get" + suffix);
+      Method hasMethod = nameToNoArgMethod.get("has" + suffix);
+      // TODO(dweis): Fix proto3 semantics.
+      if (getMethod != null) {
+        Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
+        final boolean hasValue =
+            hasMethod == null
+                ? !isDefaultValue(value)
+                : (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
+        // TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
+        if (hasValue) {
+          printField(buffer, indent, camelCaseToSnakeCase(camelCase), value);
+        }
+        continue;
+      }
+    }
+
+    if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
+      Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
+          ((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
+      while (iter.hasNext()) {
+        Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
+        printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
+      }
+    }
+
+    if (((GeneratedMessageLite<?, ?>) messageLite).unknownFields != null) {
+      ((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
+    }
+  }
+
+  private static boolean isDefaultValue(Object o) {
+    if (o instanceof Boolean) {
+      return !((Boolean) o);
+    }
+    if (o instanceof Integer) {
+      return ((Integer) o) == 0;
+    }
+    if (o instanceof Float) {
+      return ((Float) o) == 0f;
+    }
+    if (o instanceof Double) {
+      return ((Double) o) == 0d;
+    }
+    if (o instanceof String) {
+      return o.equals("");
+    }
+    if (o instanceof ByteString) {
+      return o.equals(ByteString.EMPTY);
+    }
+    if (o instanceof MessageLite) { // Can happen in oneofs.
+      return o == ((MessageLite) o).getDefaultInstanceForType();
+    }
+    if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
+      return ((java.lang.Enum<?>) o).ordinal() == 0;
+    }
+
+    return false;
+  }
+
+  /**
+   * Formats a text proto field.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces the proto should be indented by
+   * @param name the field name (in lower underscore case)
+   * @param object the object value of the field
+   */
+  static final void printField(StringBuilder buffer, int indent, String name, Object object) {
+    if (object instanceof List<?>) {
+      List<?> list = (List<?>) object;
+      for (Object entry : list) {
+        printField(buffer, indent, name, entry);
+      }
+      return;
+    }
+    if (object instanceof Map<?, ?>) {
+      Map<?, ?> map = (Map<?, ?>) object;
+      for (Map.Entry<?, ?> entry : map.entrySet()) {
+        printField(buffer, indent, name, entry);
+      }
+      return;
+    }
+
+    buffer.append('\n');
+    for (int i = 0; i < indent; i++) {
+      buffer.append(' ');
+    }
+    buffer.append(name);
+
+    if (object instanceof String) {
+      buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
+    } else if (object instanceof ByteString) {
+      buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"');
+    } else if (object instanceof GeneratedMessageLite) {
+      buffer.append(" {");
+      reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
+      buffer.append("\n");
+      for (int i = 0; i < indent; i++) {
+        buffer.append(' ');
+      }
+      buffer.append("}");
+    } else if (object instanceof Map.Entry<?, ?>) {
+      buffer.append(" {");
+      Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
+      printField(buffer, indent + 2, "key", entry.getKey());
+      printField(buffer, indent + 2, "value", entry.getValue());
+      buffer.append("\n");
+      for (int i = 0; i < indent; i++) {
+        buffer.append(' ');
+      }
+      buffer.append("}");
+    } else {
+      buffer.append(": ").append(object.toString());
+    }
+  }
+
+  private static final String camelCaseToSnakeCase(String camelCase) {
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < camelCase.length(); i++) {
+      char ch = camelCase.charAt(i);
+      if (Character.isUpperCase(ch)) {
+        builder.append("_");
+      }
+      builder.append(Character.toLowerCase(ch));
+    }
+    return builder.toString();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
index f0fc485..5e7d782 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
@@ -42,7 +42,7 @@
 public interface MessageOrBuilder extends MessageLiteOrBuilder {
 
   // (From MessageLite, re-declared here only for return type covariance.)
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   Message getDefaultInstanceForType();
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index de4bfd3..69ad7dd 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -31,7 +31,6 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.FieldDescriptor;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -370,6 +369,7 @@
 
     private final Message.Builder builder;
 
+    @Override
     public Descriptors.Descriptor getDescriptorForType() {
       return builder.getDescriptorForType();
     }
@@ -378,6 +378,7 @@
       this.builder = builder;
     }
 
+    @Override
     public Object getField(Descriptors.FieldDescriptor field) {
       return builder.getField(field);
     }
@@ -387,25 +388,27 @@
       return builder.hasField(field);
     }
 
-    public MergeTarget setField(Descriptors.FieldDescriptor field,
-        Object value) {
+    @Override
+    public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
       builder.setField(field, value);
       return this;
     }
 
+    @Override
     public MergeTarget clearField(Descriptors.FieldDescriptor field) {
       builder.clearField(field);
       return this;
     }
 
+    @Override
     public MergeTarget setRepeatedField(
         Descriptors.FieldDescriptor field, int index, Object value) {
       builder.setRepeatedField(field, index, value);
       return this;
     }
 
-    public MergeTarget addRepeatedField(
-        Descriptors.FieldDescriptor field, Object value) {
+    @Override
+    public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
       builder.addRepeatedField(field, value);
       return this;
     }
@@ -426,25 +429,30 @@
       return builder.getOneofFieldDescriptor(oneof);
     }
 
+    @Override
     public ContainerType getContainerType() {
       return ContainerType.MESSAGE;
     }
 
+    @Override
     public ExtensionRegistry.ExtensionInfo findExtensionByName(
         ExtensionRegistry registry, String name) {
       return registry.findImmutableExtensionByName(name);
     }
 
+    @Override
     public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
-        ExtensionRegistry registry, Descriptors.Descriptor containingType,
-        int fieldNumber) {
+        ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
       return registry.findImmutableExtensionByNumber(containingType,
           fieldNumber);
     }
 
-    public Object parseGroup(CodedInputStream input,
+    @Override
+    public Object parseGroup(
+        CodedInputStream input,
         ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
         throws IOException {
       Message.Builder subBuilder;
       // When default instance is not null. The field is an extension field.
@@ -463,9 +471,12 @@
       return subBuilder.buildPartial();
     }
 
-    public Object parseMessage(CodedInputStream input,
+    @Override
+    public Object parseMessage(
+        CodedInputStream input,
         ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
         throws IOException {
       Message.Builder subBuilder;
       // When default instance is not null. The field is an extension field.
@@ -484,9 +495,12 @@
       return subBuilder.buildPartial();
     }
 
-    public Object parseMessageFromBytes(ByteString bytes,
+    @Override
+    public Object parseMessageFromBytes(
+        ByteString bytes,
         ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
         throws IOException {
       Message.Builder subBuilder;
       // When default instance is not null. The field is an extension field.
@@ -505,8 +519,9 @@
       return subBuilder.buildPartial();
     }
 
-    public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
-        Message defaultInstance) {
+    @Override
+    public MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor field, Message defaultInstance) {
       if (defaultInstance != null) {
         return new BuilderAdapter(
             defaultInstance.newBuilderForType());
@@ -515,8 +530,8 @@
       }
     }
 
-    public WireFormat.Utf8Validation
-        getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+    @Override
+    public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
       if (descriptor.needsUtf8Check()) {
         return WireFormat.Utf8Validation.STRICT;
       }
@@ -528,6 +543,7 @@
       return WireFormat.Utf8Validation.LOOSE;
     }
 
+    @Override
     public Object finish() {
       return builder.buildPartial();
     }
@@ -542,38 +558,43 @@
       this.extensions = extensions;
     }
 
+    @Override
     public Descriptors.Descriptor getDescriptorForType() {
       throw new UnsupportedOperationException(
           "getDescriptorForType() called on FieldSet object");
     }
 
+    @Override
     public Object getField(Descriptors.FieldDescriptor field) {
       return extensions.getField(field);
     }
 
+    @Override
     public boolean hasField(Descriptors.FieldDescriptor field) {
       return extensions.hasField(field);
     }
 
-    public MergeTarget setField(Descriptors.FieldDescriptor field,
-        Object value) {
+    @Override
+    public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
       extensions.setField(field, value);
       return this;
     }
 
+    @Override
     public MergeTarget clearField(Descriptors.FieldDescriptor field) {
       extensions.clearField(field);
       return this;
     }
 
+    @Override
     public MergeTarget setRepeatedField(
         Descriptors.FieldDescriptor field, int index, Object value) {
       extensions.setRepeatedField(field, index, value);
       return this;
     }
 
-    public MergeTarget addRepeatedField(
-        Descriptors.FieldDescriptor field, Object value) {
+    @Override
+    public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
       extensions.addRepeatedField(field, value);
       return this;
     }
@@ -594,25 +615,31 @@
       return null;
     }
 
+    @Override
     public ContainerType getContainerType() {
       return ContainerType.EXTENSION_SET;
     }
 
+    @Override
     public ExtensionRegistry.ExtensionInfo findExtensionByName(
         ExtensionRegistry registry, String name) {
       return registry.findImmutableExtensionByName(name);
     }
 
+    @Override
     public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
-        ExtensionRegistry registry, Descriptors.Descriptor containingType,
-        int fieldNumber) {
+        ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
       return registry.findImmutableExtensionByNumber(containingType,
           fieldNumber);
     }
 
-    public Object parseGroup(CodedInputStream input,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
+    @Override
+    public Object parseGroup(
+        CodedInputStream input,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
       Message.Builder subBuilder =
           defaultInstance.newBuilderForType();
       if (!field.isRepeated()) {
@@ -625,9 +652,13 @@
       return subBuilder.buildPartial();
     }
 
-    public Object parseMessage(CodedInputStream input,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
+    @Override
+    public Object parseMessage(
+        CodedInputStream input,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
       Message.Builder subBuilder =
           defaultInstance.newBuilderForType();
       if (!field.isRepeated()) {
@@ -640,9 +671,13 @@
       return subBuilder.buildPartial();
     }
 
-    public Object parseMessageFromBytes(ByteString bytes,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
+    @Override
+    public Object parseMessageFromBytes(
+        ByteString bytes,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
       Message.Builder subBuilder =  defaultInstance.newBuilderForType();
       if (!field.isRepeated()) {
         Message originalMessage = (Message) getField(field);
@@ -654,14 +689,15 @@
       return subBuilder.buildPartial();
     }
 
+    @Override
     public MergeTarget newMergeTargetForField(
         Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
       throw new UnsupportedOperationException(
           "newMergeTargetForField() called on FieldSet object");
     }
 
-    public WireFormat.Utf8Validation
-        getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+    @Override
+    public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
       if (descriptor.needsUtf8Check()) {
         return WireFormat.Utf8Validation.STRICT;
       }
@@ -669,6 +705,7 @@
       return WireFormat.Utf8Validation.LOOSE;
     }
 
+    @Override
     public Object finish() {
       throw new UnsupportedOperationException(
           "finish() called on FieldSet object");
@@ -676,12 +713,14 @@
   }
 
   /**
-   * Parses a single field into MergeTarget. The target can be Message.Builder,
-   * FieldSet or MutableMessage.
+   * Parses a single field into MergeTarget. The target can be Message.Builder, FieldSet or
+   * MutableMessage.
    *
-   * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+   * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage.
    *
    * @param tag The tag, which should have already been read.
+   * @param unknownFields If not null, unknown fields will be merged to this {@link
+   *     UnknownFieldSet}, otherwise unknown fields will be discarded.
    * @return {@code true} unless the tag is an end-group tag.
    */
   static boolean mergeFieldFrom(
@@ -690,7 +729,8 @@
       ExtensionRegistryLite extensionRegistry,
       Descriptors.Descriptor type,
       MergeTarget target,
-      int tag) throws IOException {
+      int tag)
+      throws IOException {
     if (type.getOptions().getMessageSetWireFormat() &&
         tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
       mergeMessageSetExtensionFromCodedStream(
@@ -754,7 +794,11 @@
     }
 
     if (unknown) {  // Unknown field or wrong wire type.  Skip.
-      return unknownFields.mergeFieldFrom(tag, input);
+      if (unknownFields != null) {
+        return unknownFields.mergeFieldFrom(tag, input);
+      } else {
+        return input.skipField(tag);
+      }
     }
 
     if (packed) {
@@ -806,7 +850,9 @@
             // If the number isn't recognized as a valid value for this enum,
             // drop it.
             if (value == null) {
-              unknownFields.mergeVarintField(fieldNumber, rawValue);
+              if (unknownFields != null) {
+                unknownFields.mergeVarintField(fieldNumber, rawValue);
+              }
               return true;
             }
           }
@@ -909,7 +955,7 @@
         mergeMessageSetExtensionFromBytes(
             rawBytes, extension, extensionRegistry, target);
       } else { // We don't know how to parse this. Ignore it.
-        if (rawBytes != null) {
+        if (rawBytes != null && unknownFields != null) {
           unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
               .addLengthDelimited(rawBytes).build());
         }
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
index f71e41b..7659480 100644
--- a/java/core/src/main/java/com/google/protobuf/NioByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -30,15 +30,16 @@
 
 package com.google.protobuf;
 
-import java.io.FileOutputStream;
+import static com.google.protobuf.Internal.checkNotNull;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.nio.InvalidMarkException;
-import java.nio.channels.Channels;
 import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.List;
@@ -50,11 +51,10 @@
   private final ByteBuffer buffer;
 
   NioByteString(ByteBuffer buffer) {
-    if (buffer == null) {
-      throw new NullPointerException("buffer");
-    }
+    checkNotNull(buffer, "buffer");
 
-    this.buffer = buffer.slice();
+    // Use native byte order for fast fixed32/64 operations.
+    this.buffer = buffer.slice().order(ByteOrder.nativeOrder());
   }
 
   // =================================================================
@@ -119,7 +119,7 @@
 
   @Override
   public void writeTo(OutputStream out) throws IOException {
-    writeToInternal(out, buffer.position(), buffer.remaining());
+    out.write(toByteArray());
   }
 
   @Override
@@ -137,14 +137,12 @@
       return;
     }
 
-    // Slow path
-    if (out instanceof FileOutputStream || numberToWrite >= 8192) {
-      // Use a channel to write out the ByteBuffer.
-      Channels.newChannel(out).write(slice(sourceOffset, sourceOffset + numberToWrite));
-    } else {
-      // Just copy the data to an array and write it.
-      out.write(toByteArray());
-    }
+    ByteBufferWriter.write(slice(sourceOffset, sourceOffset + numberToWrite), out);
+  }
+
+  @Override
+  void writeTo(ByteOutput output) throws IOException {
+    output.writeLazy(buffer.slice());
   }
 
   @Override
@@ -159,46 +157,30 @@
 
   @Override
   protected String toStringInternal(Charset charset) {
-    byte[] bytes;
-    int offset;
+    final byte[] bytes;
+    final int offset;
+    final int length;
     if (buffer.hasArray()) {
       bytes = buffer.array();
       offset = buffer.arrayOffset() + buffer.position();
+      length = buffer.remaining();
     } else {
+      // TODO(nathanmittler): Can we optimize this?
       bytes = toByteArray();
       offset = 0;
+      length = bytes.length;
     }
-    return new String(bytes, offset, size(), charset);
+    return new String(bytes, offset, length, charset);
   }
 
   @Override
   public boolean isValidUtf8() {
-    // TODO(nathanmittler): add a ByteBuffer fork for Utf8.isValidUtf8 to avoid the copy
-    byte[] bytes;
-    int startIndex;
-    if (buffer.hasArray()) {
-      bytes = buffer.array();
-      startIndex = buffer.arrayOffset() + buffer.position();
-    } else {
-      bytes = toByteArray();
-      startIndex = 0;
-    }
-    return Utf8.isValidUtf8(bytes, startIndex, startIndex + size());
+    return Utf8.isValidUtf8(buffer);
   }
 
   @Override
   protected int partialIsValidUtf8(int state, int offset, int length) {
-    // TODO(nathanmittler): TODO add a ByteBuffer fork for Utf8.partialIsValidUtf8 to avoid the copy
-    byte[] bytes;
-    int startIndex;
-    if (buffer.hasArray()) {
-      bytes = buffer.array();
-      startIndex = buffer.arrayOffset() + buffer.position();
-    } else {
-      bytes = toByteArray();
-      startIndex = 0;
-    }
-    return Utf8.partialIsValidUtf8(state, bytes, startIndex, startIndex + size());
+    return Utf8.partialIsValidUtf8(state, buffer, offset, offset + length);
   }
 
   @Override
@@ -285,7 +267,7 @@
 
   @Override
   public CodedInputStream newCodedInput() {
-    return CodedInputStream.newInstance(buffer);
+    return CodedInputStream.newInstance(buffer, true);
   }
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
index 3fa11c3..e07c689 100644
--- a/java/core/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -30,8 +30,8 @@
 
 package com.google.protobuf;
 
-import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
 
 /**
  * Abstract interface for parsing Protocol Messages.
@@ -40,7 +40,7 @@
  *
  * <p>All methods may throw {@link InvalidProtocolBufferException}. In the event of invalid data,
  * like an encoding error, the cause of the thrown exception will be {@code null}. However, if an
- * I/O problem occurs, an exception is thrown with an {@link IOException} cause.
+ * I/O problem occurs, an exception is thrown with an {@link java.io.IOException} cause.
  *
  * @author liujisi@google.com (Pherl Liu)
  */
@@ -94,6 +94,18 @@
   // Convenience methods.
 
   /**
+   * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream)}.
+   */
+  public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+   */
+  public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+  /**
    * Parses {@code data} as a message of {@code MessageType}.
    * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
    */
diff --git a/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
new file mode 100644
index 0000000..79b5769
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
@@ -0,0 +1,34 @@
+// 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;
+
+/** A marker interface indicating that the collection supports primitives and is non-boxing. */
+interface PrimitiveNonBoxingCollection {}
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
index d2f82ac..81255ec 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -38,7 +38,7 @@
 /**
  * Implements {@link ProtobufList} for non-primitive and {@link String} types.
  */
-class ProtobufArrayList<E> extends AbstractProtobufList<E> {
+final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
 
   private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
   static {
@@ -51,17 +51,23 @@
   }
   
   private final List<E> list;
-  
+
   ProtobufArrayList() {
-    list = new ArrayList<E>();
+    this(new ArrayList<E>(DEFAULT_CAPACITY));
   }
   
-  ProtobufArrayList(List<E> toCopy) {
-    list = new ArrayList<E>(toCopy);
+  private ProtobufArrayList(List<E> list) {
+    this.list = list;
   }
-  
-  ProtobufArrayList(int capacity) {
-    list = new ArrayList<E>(capacity);
+
+  @Override
+  public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
+    if (capacity < size()) {
+      throw new IllegalArgumentException();
+    }
+    List<E> newList = new ArrayList<E>(capacity);
+    newList.addAll(list);
+    return new ProtobufArrayList<E>(newList);
   }
   
   @Override
diff --git a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
index 0c8df98..a596d30 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
@@ -42,6 +42,7 @@
   /**
    * Return the value's numeric value as defined in the .proto file.
    */
+  @Override
   int getNumber();
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
index f91cdbc..29f567d 100644
--- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
@@ -579,7 +579,7 @@
     }
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void markDirty() {
     onChanged();
   }
@@ -621,10 +621,12 @@
       this.builder = builder;
     }
 
+    @Override
     public int size() {
       return this.builder.getCount();
     }
 
+    @Override
     public MType get(int index) {
       return builder.getMessage(index);
     }
@@ -654,10 +656,12 @@
       this.builder = builder;
     }
 
+    @Override
     public int size() {
       return this.builder.getCount();
     }
 
+    @Override
     public BType get(int index) {
       return builder.getBuilder(index);
     }
@@ -687,10 +691,12 @@
       this.builder = builder;
     }
 
+    @Override
     public int size() {
       return this.builder.getCount();
     }
 
+    @Override
     public IType get(int index) {
       return builder.getMessageOrBuilder(index);
     }
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
new file mode 100644
index 0000000..30c991d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
@@ -0,0 +1,702 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.Internal.checkNotNull;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * {@code RepeatedFieldBuilderV3} implements a structure that a protocol
+ * message uses to hold a repeated field of other protocol messages. It supports
+ * the classical use case of adding immutable {@link Message}'s to the
+ * repeated field and is highly optimized around this (no extra memory
+ * allocations and sharing of immutable arrays).
+ * <br>
+ * It also supports the additional use case of adding a {@link Message.Builder}
+ * to the repeated field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class RepeatedFieldBuilderV3
+    <MType extends AbstractMessage,
+     BType extends AbstractMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements AbstractMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private AbstractMessage.BuilderParent parent;
+
+  // List of messages. Never null. It may be immutable, in which case
+  // isMessagesListMutable will be false. See note below.
+  private List<MType> messages;
+
+  // Whether messages is an mutable array that can be modified.
+  private boolean isMessagesListMutable;
+
+  // List of builders. May be null, in which case, no nested builders were
+  // created. If not null, entries represent the builder for that index.
+  private List<SingleFieldBuilderV3<MType, BType, IType>> builders;
+
+  // Here are the invariants for messages and builders:
+  // 1. messages is never null and its count corresponds to the number of items
+  //    in the repeated field.
+  // 2. If builders is non-null, messages and builders MUST always
+  //    contain the same number of items.
+  // 3. Entries in either array can be null, but for any index, there MUST be
+  //    either a Message in messages or a builder in builders.
+  // 4. If the builder at an index is non-null, the builder is
+  //    authoritative. This is the case where a Builder was set on the index.
+  //    Any message in the messages array MUST be ignored.
+  // t. If the builder at an index is null, the message in the messages
+  //    list is authoritative. This is the case where a Message (not a Builder)
+  //    was set directly for an index.
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
+  private boolean isClean;
+
+  // A view of this builder that exposes a List interface of messages. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a message if it
+  // was a builder.
+  private MessageExternalList<MType, BType, IType> externalMessageList;
+
+  // A view of this builder that exposes a List interface of builders. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a builder if it
+  // was a message.
+  private BuilderExternalList<MType, BType, IType> externalBuilderList;
+
+  // A view of this builder that exposes a List interface of the interface
+  // implemented by messages and builders. This is initialized on demand. This
+  // is fully backed by this object and all changes are reflected in it.
+  // Access to any item returns either a builder or message depending on
+  // what is most efficient.
+  private MessageOrBuilderExternalList<MType, BType, IType>
+      externalMessageOrBuilderList;
+
+  /**
+   * Constructs a new builder with an empty list of messages.
+   *
+   * @param messages the current list of messages
+   * @param isMessagesListMutable Whether the messages list is mutable
+   * @param parent a listener to notify of changes
+   * @param isClean whether the builder is initially marked clean
+   */
+  public RepeatedFieldBuilderV3(
+      List<MType> messages,
+      boolean isMessagesListMutable,
+      AbstractMessage.BuilderParent parent,
+      boolean isClean) {
+    this.messages = messages;
+    this.isMessagesListMutable = isMessagesListMutable;
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Ensures that the list of messages is mutable so it can be updated. If it's
+   * immutable, a copy is made.
+   */
+  private void ensureMutableMessageList() {
+    if (!isMessagesListMutable) {
+      messages = new ArrayList<MType>(messages);
+      isMessagesListMutable = true;
+    }
+  }
+
+  /**
+   * Ensures that the list of builders is not null. If it's null, the list is
+   * created and initialized to be the same size as the messages list with
+   * null entries.
+   */
+  private void ensureBuilders() {
+    if (this.builders == null) {
+      this.builders =
+          new ArrayList<SingleFieldBuilderV3<MType, BType, IType>>(
+              messages.size());
+      for (int i = 0; i < messages.size(); i++) {
+        builders.add(null);
+      }
+    }
+  }
+
+  /**
+   * Gets the count of items in the list.
+   *
+   * @return the count of items in the list.
+   */
+  public int getCount() {
+    return messages.size();
+  }
+
+  /**
+   * Gets whether the list is empty.
+   *
+   * @return whether the list is empty
+   */
+  public boolean isEmpty() {
+    return messages.isEmpty();
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @return the message for the specified index
+   */
+  public MType getMessage(int index) {
+    return getMessage(index, false);
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @param forBuild this is being called for build so we want to make sure
+   *     we SingleFieldBuilderV3.build to send dirty invalidations
+   * @return the message for the specified index
+   */
+  private MType getMessage(int index, boolean forBuild) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return messages.get(index);
+    }
+
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return messages.get(index);
+
+    } else {
+      return forBuild ? builder.build() : builder.getMessage();
+    }
+  }
+
+  /**
+   * Gets a builder for the specified index. If no builder has been created for
+   * that index, a builder is created on demand by calling
+   * {@link Message#toBuilder}.
+   *
+   * @param index the index of the message to get
+   * @return The builder for that index
+   */
+  public BType getBuilder(int index) {
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      MType message = messages.get(index);
+      builder = new SingleFieldBuilderV3<MType, BType, IType>(
+          message, this, isClean);
+      builders.set(index, builder);
+    }
+    return builder.getBuilder();
+  }
+
+  /**
+   * Gets the base class interface for the specified index. This may either be
+   * a builder or a message. It will return whatever is more efficient.
+   *
+   * @param index the index of the message to get
+   * @return the message or builder for the index as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder(int index) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return (IType) messages.get(index);
+    }
+
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return (IType) messages.get(index);
+
+    } else {
+      return builder.getMessageOrBuilder();
+    }
+  }
+
+  /**
+   * Sets a  message at the specified index replacing the existing item at
+   * that index.
+   *
+   * @param index the index to set.
+   * @param message the message to set
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
+      int index, MType message) {
+    checkNotNull(message);
+    ensureMutableMessageList();
+    messages.set(index, message);
+    if (builders != null) {
+      SingleFieldBuilderV3<MType, BType, IType> entry =
+          builders.set(index, null);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends the specified element to the end of this list.
+   *
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
+      MType message) {
+    checkNotNull(message);
+    ensureMutableMessageList();
+    messages.add(message);
+    if (builders != null) {
+      builders.add(null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Inserts the specified message at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the message
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
+      int index, MType message) {
+    checkNotNull(message);
+    ensureMutableMessageList();
+    messages.add(index, message);
+    if (builders != null) {
+      builders.add(index, null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends all of the messages in the specified collection to the end of
+   * this list, in the order that they are returned by the specified
+   * collection's iterator.
+   *
+   * @param values the messages to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
+      Iterable<? extends MType> values) {
+    for (final MType value : values) {
+      checkNotNull(value);
+    }
+
+    // If we can inspect the size, we can more efficiently add messages.
+    int size = -1;
+    if (values instanceof Collection) {
+      @SuppressWarnings("unchecked") final
+      Collection<MType> collection = (Collection<MType>) values;
+      if (collection.size() == 0) {
+        return this;
+      }
+      size = collection.size();
+    }
+    ensureMutableMessageList();
+
+    if (size >= 0 && messages instanceof ArrayList) {
+      ((ArrayList<MType>) messages)
+          .ensureCapacity(messages.size() + size);
+    }
+
+    for (MType value : values) {
+      addMessage(value);
+    }
+
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends a new builder to the end of this list and returns the builder.
+   *
+   * @param message the message to add which is the basis of the builder
+   * @return the new builder
+   */
+  public BType addBuilder(MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder =
+        new SingleFieldBuilderV3<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(null);
+    builders.add(builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Inserts a new builder at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the builder
+   * @param message the message to add which is the basis of the builder
+   * @return the builder
+   */
+  public BType addBuilder(int index, MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder =
+        new SingleFieldBuilderV3<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(index, null);
+    builders.add(index, builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Removes the element at the specified position in this list. Shifts any
+   * subsequent elements to the left (subtracts one from their indices).
+   * Returns the element that was removed from the list.
+   *
+   * @param index the index at which to remove the message
+   */
+  public void remove(int index) {
+    ensureMutableMessageList();
+    messages.remove(index);
+    if (builders != null) {
+      SingleFieldBuilderV3<MType, BType, IType> entry =
+          builders.remove(index);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Removes all of the elements from this list.
+   * The list will be empty after this call returns.
+   */
+  public void clear() {
+    messages = Collections.emptyList();
+    isMessagesListMutable = false;
+    if (builders != null) {
+      for (SingleFieldBuilderV3<MType, BType, IType> entry :
+          builders) {
+        if (entry != null) {
+          entry.dispose();
+        }
+      }
+      builders = null;
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Builds the list of messages from the builder and returns them.
+   *
+   * @return an immutable list of messages
+   */
+  public List<MType> build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+
+    if (!isMessagesListMutable && builders == null) {
+      // We still have an immutable list and we never created a builder.
+      return messages;
+    }
+
+    boolean allMessagesInSync = true;
+    if (!isMessagesListMutable) {
+      // We still have an immutable list. Let's see if any of them are out
+      // of sync with their builders.
+      for (int i = 0; i < messages.size(); i++) {
+        Message message = messages.get(i);
+        SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(i);
+        if (builder != null) {
+          if (builder.build() != message) {
+            allMessagesInSync = false;
+            break;
+          }
+        }
+      }
+      if (allMessagesInSync) {
+        // Immutable list is still in sync.
+        return messages;
+      }
+    }
+
+    // Need to make sure messages is up to date
+    ensureMutableMessageList();
+    for (int i = 0; i < messages.size(); i++) {
+      messages.set(i, getMessage(i, true));
+    }
+
+    // We're going to return our list as immutable so we mark that we can
+    // no longer update it.
+    messages = Collections.unmodifiableList(messages);
+    isMessagesListMutable = false;
+    return messages;
+  }
+
+  /**
+   * Gets a view of the builder as a list of messages. The returned list is live
+   * and will reflect any changes to the underlying builder.
+   *
+   * @return the messages in the list
+   */
+  public List<MType> getMessageList() {
+    if (externalMessageList == null) {
+      externalMessageList =
+          new MessageExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of builders. This returned list is
+   * live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<BType> getBuilderList() {
+    if (externalBuilderList == null) {
+      externalBuilderList =
+          new BuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalBuilderList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of MessageOrBuilders. This returned
+   * list is live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<IType> getMessageOrBuilderList() {
+    if (externalMessageOrBuilderList == null) {
+      externalMessageOrBuilderList =
+          new MessageOrBuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageOrBuilderList;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+
+  /**
+   * Increments the mod counts so that an ConcurrentModificationException can
+   * be thrown if calling code tries to modify the builder while its iterating
+   * the list.
+   */
+  private void incrementModCounts() {
+    if (externalMessageList != null) {
+      externalMessageList.incrementModCount();
+    }
+    if (externalBuilderList != null) {
+      externalBuilderList.incrementModCount();
+    }
+    if (externalMessageOrBuilderList != null) {
+      externalMessageOrBuilderList.incrementModCount();
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of messages.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<MType> implements List<MType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    MessageExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public MType get(int index) {
+      return builder.getMessage(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class BuilderExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<BType> implements List<BType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    BuilderExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public BType get(int index) {
+      return builder.getBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageOrBuilderExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<IType> implements List<IType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    MessageOrBuilderExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public IType get(int index) {
+      return builder.getMessageOrBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
index 8badfab..6fa555d 100644
--- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -48,10 +48,11 @@
 /**
  * Class to represent {@code ByteStrings} formed by concatenation of other
  * ByteStrings, without copying the data in the pieces. The concatenation is
- * represented as a tree whose leaf nodes are each a {@link LiteralByteString}.
+ * represented as a tree whose leaf nodes are each a
+ * {@link com.google.protobuf.ByteString.LeafByteString}.
  *
  * <p>Most of the operation here is inspired by the now-famous paper <a
- * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+ * href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
  * BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
  * michael plass
  *
@@ -139,8 +140,9 @@
   /**
    * Concatenate the given strings while performing various optimizations to
    * slow the growth rate of tree depth and tree node count. The result is
-   * either a {@link LiteralByteString} or a {@link RopeByteString}
-   * depending on which optimizations, if any, were applied.
+   * either a {@link com.google.protobuf.ByteString.LeafByteString} or a
+   * {@link RopeByteString} depending on which optimizations, if any, were
+   * applied.
    *
    * <p>Small pieces of length less than {@link
    * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
@@ -294,8 +296,7 @@
    *
    * <p>Substrings of {@code length < 2} should result in at most a single
    * recursive call chain, terminating at a leaf node. Thus the result will be a
-   * {@link LiteralByteString}. {@link #RopeByteString(ByteString,
-   * ByteString)}.
+   * {@link com.google.protobuf.ByteString.LeafByteString}.
    *
    * @param beginIndex start at this index
    * @param endIndex   the last character is the one before this index
@@ -368,7 +369,7 @@
 
   @Override
   public List<ByteBuffer> asReadOnlyByteBufferList() {
-    // Walk through the list of LiteralByteString's that make up this
+    // Walk through the list of LeafByteString's that make up this
     // rope, and add each one as a read-only ByteBuffer.
     List<ByteBuffer> result = new ArrayList<ByteBuffer>();
     PieceIterator pieces = new PieceIterator(this);
@@ -400,6 +401,13 @@
   }
 
   @Override
+  void writeTo(ByteOutput output) throws IOException {
+    left.writeTo(output);
+    right.writeTo(output);
+  }
+
+
+  @Override
   protected String toStringInternal(Charset charset) {
     return new String(toByteArray(), charset);
   }
@@ -709,9 +717,10 @@
     }
 
     /**
-     * Returns the next item and advances one {@code LiteralByteString}.
+     * Returns the next item and advances one
+     * {@link com.google.protobuf.ByteString.LeafByteString}.
      *
-     * @return next non-empty LiteralByteString or {@code null}
+     * @return next non-empty LeafByteString or {@code null}
      */
     @Override
     public LeafByteString next() {
diff --git a/java/core/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
index 694b8d1..f7d555a 100644
--- a/java/core/src/main/java/com/google/protobuf/RpcUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
@@ -71,6 +71,7 @@
       final Class<Type> originalClass,
       final Type defaultInstance) {
     return new RpcCallback<Message>() {
+      @Override
       public void run(final Message parameter) {
         Type typedParameter;
         try {
@@ -107,8 +108,9 @@
     return new RpcCallback<ParameterType>() {
       private boolean alreadyCalled = false;
 
+      @Override
       public void run(final ParameterType parameter) {
-        synchronized(this) {
+        synchronized (this) {
           if (alreadyCalled) {
             throw new AlreadyCalledException();
           }
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
index aba65e3..941b5de 100644
--- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
@@ -234,7 +234,7 @@
     }
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void markDirty() {
     onChanged();
   }
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
new file mode 100644
index 0000000..8ab0f26
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
@@ -0,0 +1,237 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.Internal.checkNotNull;
+
+/**
+ * {@code SingleFieldBuilderV3} implements a structure that a protocol
+ * message uses to hold a single field of another protocol message. It supports
+ * the classical use case of setting an immutable {@link Message} as the value
+ * of the field and is highly optimized around this.
+ * <br>
+ * It also supports the additional use case of setting a {@link Message.Builder}
+ * as the field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class SingleFieldBuilderV3
+    <MType extends AbstractMessage,
+     BType extends AbstractMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements AbstractMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private AbstractMessage.BuilderParent parent;
+
+  // Invariant: one of builder or message fields must be non-null.
+
+  // If set, this is the case where we are backed by a builder. In this case,
+  // message field represents a cached message for the builder (or null if
+  // there is no cached message).
+  private BType builder;
+
+  // If builder is non-null, this represents a cached message from the builder.
+  // If builder is null, this is the authoritative message for the field.
+  private MType message;
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
+  private boolean isClean;
+
+  public SingleFieldBuilderV3(
+      MType message,
+      AbstractMessage.BuilderParent parent,
+      boolean isClean) {
+    this.message = checkNotNull(message);
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Get the message for the field. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it. If no message has
+   * been set, returns the default instance of the message.
+   *
+   * @return the message for the field
+   */
+  @SuppressWarnings("unchecked")
+  public MType getMessage() {
+    if (message == null) {
+      // If message is null, the invariant is that we must be have a builder.
+      message = (MType) builder.buildPartial();
+    }
+    return message;
+  }
+
+  /**
+   * Builds the message and returns it.
+   *
+   * @return the message
+   */
+  public MType build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+    return getMessage();
+  }
+
+  /**
+   * Gets a builder for the field. If no builder has been created yet, a
+   * builder is created on demand by calling {@link Message#toBuilder}.
+   *
+   * @return The builder for the field
+   */
+  @SuppressWarnings("unchecked")
+  public BType getBuilder() {
+    if (builder == null) {
+      // builder.mergeFrom() on a fresh builder
+      // does not create any sub-objects with independent clean/dirty states,
+      // therefore setting the builder itself to clean without actually calling
+      // build() cannot break any invariants.
+      builder = (BType) message.newBuilderForType(this);
+      builder.mergeFrom(message); // no-op if message is the default message
+      builder.markClean();
+    }
+    return builder;
+  }
+
+  /**
+   * Gets the base class interface for the field. This may either be a builder
+   * or a message. It will return whatever is more efficient.
+   *
+   * @return the message or builder for the field as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder() {
+    if (builder != null) {
+      return  (IType) builder;
+    } else {
+      return (IType) message;
+    }
+  }
+
+  /**
+   * Sets a  message for the field replacing any existing value.
+   *
+   * @param message the message to set
+   * @return the builder
+   */
+  public SingleFieldBuilderV3<MType, BType, IType> setMessage(
+      MType message) {
+    this.message = checkNotNull(message);
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Merges the field from another field.
+   *
+   * @param value the value to merge from
+   * @return the builder
+   */
+  public SingleFieldBuilderV3<MType, BType, IType> mergeFrom(
+      MType value) {
+    if (builder == null && message == message.getDefaultInstanceForType()) {
+      message = value;
+    } else {
+      getBuilder().mergeFrom(value);
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Clears the value of the field.
+   *
+   * @return the builder
+   */
+  @SuppressWarnings("unchecked")
+  public SingleFieldBuilderV3<MType, BType, IType> clear() {
+    message = (MType) (message != null ?
+        message.getDefaultInstanceForType() :
+        builder.getDefaultInstanceForType());
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    // If builder is null, this is the case where onChanged is being called
+    // from setMessage or clear.
+    if (builder != null) {
+      message = null;
+    }
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
index 0674d2e..279edc4 100644
--- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -35,12 +35,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.TreeMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedMap;
+import java.util.TreeMap;
 
 /**
  * A custom map implementation from FieldDescriptor to Object optimized to
@@ -197,6 +197,7 @@
         overflowEntries.entrySet();
   }
 
+
   @Override
   public int size() {
     return entryList.size() + overflowEntries.size();
@@ -356,6 +357,7 @@
     return lazyEntrySet;
   }
 
+
   /**
    * @throws UnsupportedOperationException if {@link #makeImmutable()} has
    *         has been called.
@@ -411,22 +413,22 @@
       this.value = value;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public K getKey() {
       return key;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public V getValue() {
       return value;
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public int compareTo(Entry other) {
       return getKey().compareTo(other.getKey());
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public V setValue(V newValue) {
       checkMutable();
       final V oldValue = this.value;
@@ -525,6 +527,7 @@
     }
   }
 
+
   /**
    * Iterator implementation that switches from the entry array to the overflow
    * entries appropriately.
@@ -535,13 +538,13 @@
     private boolean nextCalledBeforeRemove;
     private Iterator<Map.Entry<K, V>> lazyOverflowIterator;
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public boolean hasNext() {
-      return (pos + 1) < entryList.size() ||
-          getOverflowIterator().hasNext();
+      return (pos + 1) < entryList.size()
+          || (!overflowEntries.isEmpty() && getOverflowIterator().hasNext());
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public Map.Entry<K, V> next() {
       nextCalledBeforeRemove = true;
       // Always increment pos so that we know whether the last returned value
@@ -552,7 +555,7 @@
       return getOverflowIterator().next();
     }
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public void remove() {
       if (!nextCalledBeforeRemove) {
         throw new IllegalStateException("remove() was called before next()");
@@ -588,31 +591,83 @@
    */
   private static class EmptySet {
 
-    private static final Iterator<Object> ITERATOR = new Iterator<Object>() {
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public boolean hasNext() {
-        return false;
-      }
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public Object next() {
-        throw new NoSuchElementException();
-      }
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-    };
+    private static final Iterator<Object> ITERATOR =
+        new Iterator<Object>() {
+          @Override
+          public boolean hasNext() {
+            return false;
+          }
+          @Override
+          public Object next() {
+            throw new NoSuchElementException();
+          }
+          @Override
+          public void remove() {
+            throw new UnsupportedOperationException();
+          }
+        };
 
-    private static final Iterable<Object> ITERABLE = new Iterable<Object>() {
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public Iterator<Object> iterator() {
-        return ITERATOR;
-      }
-    };
+    private static final Iterable<Object> ITERABLE =
+        new Iterable<Object>() {
+          @Override
+          public Iterator<Object> iterator() {
+            return ITERATOR;
+          }
+        };
 
     @SuppressWarnings("unchecked")
     static <T> Iterable<T> iterable() {
       return (Iterable<T>) ITERABLE;
     }
   }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+
+    if (!(o instanceof SmallSortedMap)) {
+      return super.equals(o);
+    }
+
+    SmallSortedMap<?, ?> other = (SmallSortedMap<?, ?>) o;
+    final int size = size();
+    if (size != other.size()) {
+      return false;
+    }
+
+    // Best effort try to avoid allocating an entry set.
+    final int numArrayEntries = getNumArrayEntries();
+    if (numArrayEntries != other.getNumArrayEntries()) {
+      return entrySet().equals(other.entrySet());
+    }
+
+    for (int i = 0; i < numArrayEntries; i++) {
+      if (!getArrayEntryAt(i).equals(other.getArrayEntryAt(i))) {
+        return false;
+      }
+    }
+
+    if (numArrayEntries != size) {
+      return overflowEntries.equals(other.overflowEntries);
+    }
+
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int h = 0;
+    final int listSize = getNumArrayEntries();
+    for (int i = 0; i < listSize; i++) {
+      h += entryList.get(i).hashCode();
+    }
+    // Avoid the iterator allocation if possible.
+    if (getNumOverflowEntries() > 0) {
+      h += overflowEntries.hashCode();
+    }
+    return h;
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index c99b528..25c3474 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -34,7 +34,6 @@
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-
 import java.io.IOException;
 import java.math.BigInteger;
 import java.nio.CharBuffer;
@@ -56,14 +55,7 @@
 public final class TextFormat {
   private TextFormat() {}
 
-  private static final Logger logger =
-      Logger.getLogger(TextFormat.class.getName());
-
-  private static final Printer DEFAULT_PRINTER = new Printer();
-  private static final Printer SINGLE_LINE_PRINTER =
-      (new Printer()).setSingleLineMode(true);
-  private static final Printer UNICODE_PRINTER =
-      (new Printer()).setEscapeNonAscii(false);
+  private static final Logger logger = Logger.getLogger(TextFormat.class.getName());
 
   /**
    * Outputs a textual representation of the Protocol Message supplied into
@@ -73,14 +65,14 @@
   public static void print(
       final MessageOrBuilder message, final Appendable output)
       throws IOException {
-    DEFAULT_PRINTER.print(message, new TextGenerator(output));
+    Printer.DEFAULT.print(message, multiLineOutput(output));
   }
 
   /** Outputs a textual representation of {@code fields} to {@code output}. */
   public static void print(final UnknownFieldSet fields,
                            final Appendable output)
                            throws IOException {
-    DEFAULT_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+    Printer.DEFAULT.printUnknownFields(fields, multiLineOutput(output));
   }
 
   /**
@@ -90,7 +82,7 @@
   public static void printUnicode(
       final MessageOrBuilder message, final Appendable output)
       throws IOException {
-    UNICODE_PRINTER.print(message, new TextGenerator(output));
+    Printer.UNICODE.print(message, multiLineOutput(output));
   }
 
   /**
@@ -100,7 +92,7 @@
   public static void printUnicode(final UnknownFieldSet fields,
                                   final Appendable output)
                                   throws IOException {
-    UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+    Printer.UNICODE.printUnknownFields(fields, multiLineOutput(output));
   }
 
   /**
@@ -109,10 +101,9 @@
    */
   public static String shortDebugString(final MessageOrBuilder message) {
     try {
-      final StringBuilder sb = new StringBuilder();
-      SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb));
-      // Single line mode currently might have an extra space at the end.
-      return sb.toString().trim();
+      final StringBuilder text = new StringBuilder();
+      Printer.DEFAULT.print(message, singleLineOutput(text));
+      return text.toString();
     } catch (IOException e) {
       throw new IllegalStateException(e);
     }
@@ -125,11 +116,11 @@
   public static String shortDebugString(final FieldDescriptor field,
                                         final Object value) {
     try {
-      final StringBuilder sb = new StringBuilder();
-      SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
-      return sb.toString().trim();
+      final StringBuilder text = new StringBuilder();
+      Printer.DEFAULT.printField(field, value, singleLineOutput(text));
+      return text.toString();
     } catch (IOException e) {
-        throw new IllegalStateException(e);
+      throw new IllegalStateException(e);
     }
   }
 
@@ -139,10 +130,9 @@
    */
   public static String shortDebugString(final UnknownFieldSet fields) {
     try {
-      final StringBuilder sb = new StringBuilder();
-      SINGLE_LINE_PRINTER.printUnknownFields(fields, new TextGenerator(sb));
-      // Single line mode currently might have an extra space at the end.
-      return sb.toString().trim();
+      final StringBuilder text = new StringBuilder();
+      Printer.DEFAULT.printUnknownFields(fields, singleLineOutput(text));
+      return text.toString();
     } catch (IOException e) {
       throw new IllegalStateException(e);
     }
@@ -183,7 +173,7 @@
   public static String printToUnicodeString(final MessageOrBuilder message) {
     try {
       final StringBuilder text = new StringBuilder();
-      UNICODE_PRINTER.print(message, new TextGenerator(text));
+      Printer.UNICODE.print(message, multiLineOutput(text));
       return text.toString();
     } catch (IOException e) {
       throw new IllegalStateException(e);
@@ -197,7 +187,7 @@
   public static String printToUnicodeString(final UnknownFieldSet fields) {
     try {
       final StringBuilder text = new StringBuilder();
-      UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text));
+      Printer.UNICODE.printUnknownFields(fields, multiLineOutput(text));
       return text.toString();
     } catch (IOException e) {
       throw new IllegalStateException(e);
@@ -208,7 +198,7 @@
                                 final Object value,
                                 final Appendable output)
                                 throws IOException {
-    DEFAULT_PRINTER.printField(field, value, new TextGenerator(output));
+    Printer.DEFAULT.printField(field, value, multiLineOutput(output));
   }
 
   public static String printFieldToString(final FieldDescriptor field,
@@ -223,6 +213,23 @@
   }
 
   /**
+   * Outputs a unicode textual representation of the value of given field value.
+   *
+   * <p>Same as {@code printFieldValue()}, except that non-ASCII characters in string type fields
+   * are not escaped in backslash+octals.
+   *
+   * @param field the descriptor of the field
+   * @param value the value of the field
+   * @param output the output to which to append the formatted value
+   * @throws ClassCastException if the value is not appropriate for the given field descriptor
+   * @throws IOException if there is an exception writing to the output
+   */
+  public static void printUnicodeFieldValue(
+      final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
+    Printer.UNICODE.printFieldValue(field, value, multiLineOutput(output));
+  }
+
+  /**
    * Outputs a textual representation of the value of given field value.
    *
    * @param field the descriptor of the field
@@ -236,7 +243,7 @@
                                      final Object value,
                                      final Appendable output)
                                      throws IOException {
-    DEFAULT_PRINTER.printFieldValue(field, value, new TextGenerator(output));
+    Printer.DEFAULT.printFieldValue(field, value, multiLineOutput(output));
   }
 
   /**
@@ -253,7 +260,7 @@
                                             final Object value,
                                             final Appendable output)
                                             throws IOException {
-    printUnknownFieldValue(tag, value, new TextGenerator(output));
+    printUnknownFieldValue(tag, value, multiLineOutput(output));
   }
 
   private static void printUnknownFieldValue(final int tag,
@@ -272,12 +279,24 @@
         generator.print(String.format((Locale) null, "0x%016x", (Long) value));
         break;
       case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-        generator.print("\"");
-        generator.print(escapeBytes((ByteString) value));
-        generator.print("\"");
+        try {
+          // Try to parse and print the field as an embedded message
+          UnknownFieldSet message = UnknownFieldSet.parseFrom((ByteString) value);
+          generator.print("{");
+          generator.eol();
+          generator.indent();
+          Printer.DEFAULT.printUnknownFields(message, generator);
+          generator.outdent();
+          generator.print("}");
+        } catch (InvalidProtocolBufferException e) {
+          // If not parseable as a message, print as a String
+          generator.print("\"");
+          generator.print(escapeBytes((ByteString) value));
+          generator.print("\"");
+        }
         break;
       case WireFormat.WIRETYPE_START_GROUP:
-        DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator);
+        Printer.DEFAULT.printUnknownFields((UnknownFieldSet) value, generator);
         break;
       default:
         throw new IllegalArgumentException("Bad tag: " + tag);
@@ -286,24 +305,16 @@
 
   /** Helper class for converting protobufs to text. */
   private static final class Printer {
-    /** Whether to omit newlines from the output. */
-    boolean singleLineMode = false;
+    // Printer instance which escapes non-ASCII characters.
+    static final Printer DEFAULT = new Printer(true);
+    // Printer instance which emits Unicode (it still escapes newlines and quotes in strings).
+    static final Printer UNICODE = new Printer(false);
 
     /** Whether to escape non ASCII characters with backslash and octal. */
-    boolean escapeNonAscii = true;
+    private final boolean escapeNonAscii;
 
-    private Printer() {}
-
-    /** Setter of singleLineMode */
-    private Printer setSingleLineMode(boolean singleLineMode) {
-      this.singleLineMode = singleLineMode;
-      return this;
-    }
-
-    /** Setter of escapeNonAscii */
-    private Printer setEscapeNonAscii(boolean escapeNonAscii) {
+    private Printer(boolean escapeNonAscii) {
       this.escapeNonAscii = escapeNonAscii;
-      return this;
     }
 
     private void print(
@@ -355,12 +366,9 @@
       }
 
       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (singleLineMode) {
-          generator.print(" { ");
-        } else {
-          generator.print(" {\n");
-          generator.indent();
-        }
+        generator.print(" {");
+        generator.eol();
+        generator.indent();
       } else {
         generator.print(": ");
       }
@@ -368,19 +376,10 @@
       printFieldValue(field, value, generator);
 
       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (singleLineMode) {
-          generator.print("} ");
-        } else {
-          generator.outdent();
-          generator.print("}\n");
-        }
-      } else {
-        if (singleLineMode) {
-          generator.print(" ");
-        } else {
-          generator.print("\n");
-        }
+        generator.outdent();
+        generator.print("}");
       }
+      generator.eol();
     }
 
     private void printFieldValue(final FieldDescriptor field,
@@ -425,7 +424,7 @@
         case STRING:
           generator.print("\"");
           generator.print(escapeNonAscii
-              ? escapeText((String) value)
+              ? TextFormatEscaper.escapeText((String) value)
               : escapeDoubleQuotesAndBackslashes((String) value)
                   .replace("\n", "\\n"));
           generator.print("\"");
@@ -469,19 +468,13 @@
             field.getLengthDelimitedList(), generator);
         for (final UnknownFieldSet value : field.getGroupList()) {
           generator.print(entry.getKey().toString());
-          if (singleLineMode) {
-            generator.print(" { ");
-          } else {
-            generator.print(" {\n");
-            generator.indent();
-          }
+          generator.print(" {");
+          generator.eol();
+          generator.indent();
           printUnknownFields(value, generator);
-          if (singleLineMode) {
-            generator.print("} ");
-          } else {
-            generator.outdent();
-            generator.print("}\n");
-          }
+          generator.outdent();
+          generator.print("}");
+          generator.eol();
         }
       }
     }
@@ -495,7 +488,7 @@
         generator.print(String.valueOf(number));
         generator.print(": ");
         printUnknownFieldValue(wireType, value, generator);
-        generator.print(singleLineMode ? " " : "\n");
+        generator.eol();
       }
     }
   }
@@ -521,16 +514,29 @@
     }
   }
 
-  /**
+  private static TextGenerator multiLineOutput(Appendable output) {
+    return new TextGenerator(output, false);
+  }
+
+  private static TextGenerator singleLineOutput(Appendable output) {
+    return new TextGenerator(output, true);
+  }
+
+ /**
    * An inner class for writing text to the output stream.
    */
   private static final class TextGenerator {
     private final Appendable output;
     private final StringBuilder indent = new StringBuilder();
-    private boolean atStartOfLine = true;
+    private final boolean singleLineMode;
+    // While technically we are "at the start of a line" at the very beginning of the output, all
+    // we would do in response to this is emit the (zero length) indentation, so it has no effect.
+    // Setting it false here does however suppress an unwanted leading space in single-line mode.
+    private boolean atStartOfLine = false;
 
-    private TextGenerator(final Appendable output) {
+    private TextGenerator(final Appendable output, boolean singleLineMode) {
       this.output = output;
+      this.singleLineMode = singleLineMode;
     }
 
     /**
@@ -552,35 +558,31 @@
         throw new IllegalArgumentException(
             " Outdent() without matching Indent().");
       }
-      indent.delete(length - 2, length);
+      indent.setLength(length - 2);
     }
 
     /**
-     * Print text to the output stream.
+     * Print text to the output stream. Bare newlines are never expected to be passed to this
+     * method; to indicate the end of a line, call "eol()".
      */
     public void print(final CharSequence text) throws IOException {
-      final int size = text.length();
-      int pos = 0;
-
-      for (int i = 0; i < size; i++) {
-        if (text.charAt(i) == '\n') {
-          write(text.subSequence(pos, i + 1));
-          pos = i + 1;
-          atStartOfLine = true;
-        }
-      }
-      write(text.subSequence(pos, size));
-    }
-
-    private void write(final CharSequence data) throws IOException {
-      if (data.length() == 0) {
-        return;
-      }
       if (atStartOfLine) {
         atStartOfLine = false;
-        output.append(indent);
+        output.append(singleLineMode ? " " : indent);
       }
-      output.append(data);
+      output.append(text);
+    }
+
+    /**
+     * Signifies reaching the "end of the current line" in the output. In single-line mode, this
+     * does not result in a newline being emitted, but ensures that a separating space is written
+     * before the next output.
+     */
+    public void eol() throws IOException {
+      if (!singleLineMode) {
+        output.append("\n");
+      }
+      atStartOfLine = true;
     }
   }
 
@@ -661,6 +663,22 @@
       nextToken();
     }
 
+    int getPreviousLine() {
+      return previousLine;
+    }
+
+    int getPreviousColumn() {
+      return previousColumn;
+    }
+
+    int getLine() {
+      return line;
+    }
+
+    int getColumn() {
+      return column;
+    }
+
     /** Are we at the end of the input? */
     public boolean atEnd() {
       return currentToken.length() == 0;
@@ -957,17 +975,19 @@
      */
     public boolean consumeBoolean() throws ParseException {
       if (currentToken.equals("true")
+          || currentToken.equals("True")
           || currentToken.equals("t")
           || currentToken.equals("1")) {
         nextToken();
         return true;
       } else if (currentToken.equals("false")
+          || currentToken.equals("False")
           || currentToken.equals("f")
           || currentToken.equals("0")) {
         nextToken();
         return false;
       } else {
-        throw parseException("Expected \"true\" or \"false\".");
+        throw parseException("Expected \"true\" or \"false\". Found \"" + currentToken + "\".");
       }
     }
 
@@ -1074,7 +1094,7 @@
     private ParseException floatParseException(final NumberFormatException e) {
       return parseException("Couldn't parse number: " + e.getMessage());
     }
-    
+
     /**
      * Returns a {@link UnknownFieldParseException} with the line and column
      * numbers of the previous token in the description, and the unknown field
@@ -1133,7 +1153,7 @@
       return column;
     }
   }
-  
+
   /**
    * Thrown when encountering an unknown field while parsing
    * a text format message.
@@ -1204,6 +1224,22 @@
   }
 
   /**
+   * Parse a text-format message from {@code input}.
+   *
+   * @return the parsed message, guaranteed initialized
+   */
+  public static <T extends Message> T parse(final CharSequence input,
+                                            final Class<T> protoClass)
+                                            throws ParseException {
+    Message.Builder builder =
+        Internal.getDefaultInstance(protoClass).newBuilderForType();
+    merge(input, builder);
+    @SuppressWarnings("unchecked")
+    T output = (T) builder.build();
+    return output;
+  }
+
+  /**
    * Parse a text-format message from {@code input} and merge the contents
    * into {@code builder}.  Extensions will be recognized if they are
    * registered in {@code extensionRegistry}.
@@ -1228,6 +1264,25 @@
     PARSER.merge(input, extensionRegistry, builder);
   }
 
+  /**
+   * Parse a text-format message from {@code input}.  Extensions will be
+   * recognized if they are registered in {@code extensionRegistry}.
+   *
+   * @return the parsed message, guaranteed initialized
+   */
+  public static <T extends Message> T parse(
+      final CharSequence input,
+      final ExtensionRegistry extensionRegistry,
+      final Class<T> protoClass)
+      throws ParseException {
+    Message.Builder builder =
+        Internal.getDefaultInstance(protoClass).newBuilderForType();
+    merge(input, extensionRegistry, builder);
+    @SuppressWarnings("unchecked")
+    T output = (T) builder.build();
+    return output;
+  }
+
 
   /**
    * Parser for text-format proto2 instances. This class is thread-safe.
@@ -1256,12 +1311,19 @@
     }
 
     private final boolean allowUnknownFields;
+    private final boolean allowUnknownEnumValues;
     private final SingularOverwritePolicy singularOverwritePolicy;
+    private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
 
-    private Parser(boolean allowUnknownFields,
-        SingularOverwritePolicy singularOverwritePolicy) {
+    private Parser(
+        boolean allowUnknownFields,
+        boolean allowUnknownEnumValues,
+        SingularOverwritePolicy singularOverwritePolicy,
+        TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
       this.allowUnknownFields = allowUnknownFields;
+      this.allowUnknownEnumValues = allowUnknownEnumValues;
       this.singularOverwritePolicy = singularOverwritePolicy;
+      this.parseInfoTreeBuilder = parseInfoTreeBuilder;
     }
 
     /**
@@ -1276,8 +1338,10 @@
      */
     public static class Builder {
       private boolean allowUnknownFields = false;
+      private boolean allowUnknownEnumValues = false;
       private SingularOverwritePolicy singularOverwritePolicy =
           SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
+      private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
 
 
       /**
@@ -1288,8 +1352,18 @@
         return this;
       }
 
+      public Builder setParseInfoTreeBuilder(
+          TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
+        this.parseInfoTreeBuilder = parseInfoTreeBuilder;
+        return this;
+      }
+
       public Parser build() {
-        return new Parser(allowUnknownFields, singularOverwritePolicy);
+        return new Parser(
+            allowUnknownFields,
+            allowUnknownEnumValues,
+            singularOverwritePolicy,
+            parseInfoTreeBuilder);
       }
     }
 
@@ -1353,6 +1427,28 @@
       return text;
     }
 
+    // Check both unknown fields and unknown extensions and log warning messages
+    // or throw exceptions according to the flag.
+    private void checkUnknownFields(final List<String> unknownFields)
+        throws ParseException {
+      if (unknownFields.isEmpty()) {
+        return;
+      }
+
+      StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:");
+      for (String field : unknownFields) {
+        msg.append('\n').append(field);
+      }
+
+      if (allowUnknownFields) {
+          logger.warning(msg.toString());
+      } else {
+        String[] lineColumn = unknownFields.get(0).split(":");
+        throw new ParseException(Integer.valueOf(lineColumn[0]),
+            Integer.valueOf(lineColumn[1]), msg.toString());
+      }
+    }
+
     /**
      * Parse a text-format message from {@code input} and merge the contents
      * into {@code builder}.  Extensions will be recognized if they are
@@ -1366,9 +1462,13 @@
       MessageReflection.BuilderAdapter target =
           new MessageReflection.BuilderAdapter(builder);
 
+      List<String> unknownFields = new ArrayList<String>();
+
       while (!tokenizer.atEnd()) {
-        mergeField(tokenizer, extensionRegistry, target);
+        mergeField(tokenizer, extensionRegistry, target, unknownFields);
       }
+
+      checkUnknownFields(unknownFields);
     }
 
 
@@ -1378,9 +1478,26 @@
      */
     private void mergeField(final Tokenizer tokenizer,
                             final ExtensionRegistry extensionRegistry,
-                            final MessageReflection.MergeTarget target)
+                            final MessageReflection.MergeTarget target,
+                            List<String> unknownFields)
+                            throws ParseException {
+      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder,
+                 unknownFields);
+    }
+
+    /**
+     * Parse a single field from {@code tokenizer} and merge it into
+     * {@code target}.
+     */
+    private void mergeField(final Tokenizer tokenizer,
+                            final ExtensionRegistry extensionRegistry,
+                            final MessageReflection.MergeTarget target,
+                            TextFormatParseInfoTree.Builder parseTreeBuilder,
+                            List<String> unknownFields)
                             throws ParseException {
       FieldDescriptor field = null;
+      int startLine = tokenizer.getLine();
+      int startColumn = tokenizer.getColumn();
       final Descriptor type = target.getDescriptorForType();
       ExtensionRegistry.ExtensionInfo extension = null;
 
@@ -1397,13 +1514,15 @@
             extensionRegistry, name.toString());
 
         if (extension == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.parseExceptionPreviousToken(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          } else {
-            logger.warning(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          }
+          unknownFields.add(
+              (tokenizer.getPreviousLine() + 1)
+                  + ":"
+                  + (tokenizer.getPreviousColumn() + 1)
+                  + ":\t"
+                  + type.getFullName()
+                  + ".["
+                  + name
+                  + "]");
         } else {
           if (extension.descriptor.getContainingType() != type) {
             throw tokenizer.parseExceptionPreviousToken(
@@ -1438,16 +1557,14 @@
         }
 
         if (field == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.unknownFieldParseExceptionPreviousToken(
-              name,
-              "Message type \"" + type.getFullName()
-              + "\" has no field named \"" + name + "\".");
-          } else {
-            logger.warning(
-              "Message type \"" + type.getFullName()
-              + "\" has no field named \"" + name + "\".");
-          }
+          unknownFields.add(
+              (tokenizer.getPreviousLine() + 1)
+                  + ":"
+                  + (tokenizer.getPreviousColumn() + 1)
+                  + ":\t"
+                  + type.getFullName()
+                  + "."
+                  + name);
         }
       }
 
@@ -1472,22 +1589,24 @@
       // Handle potential ':'.
       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
         tokenizer.tryConsume(":");  // optional
-      } else {
-        tokenizer.consume(":");  // required
-      }
-      // Support specifying repeated field values as a comma-separated list.
-      // Ex."foo: [1, 2, 3]"
-      if (field.isRepeated() && tokenizer.tryConsume("[")) {
-        while (true) {
-          consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
-          if (tokenizer.tryConsume("]")) {
-            // End of list.
-            break;
-          }
-          tokenizer.consume(",");
+        if (parseTreeBuilder != null) {
+          TextFormatParseInfoTree.Builder childParseTreeBuilder =
+              parseTreeBuilder.getBuilderForSubMessageField(field);
+          consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+              childParseTreeBuilder, unknownFields);
+        } else {
+          consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+              parseTreeBuilder, unknownFields);
         }
       } else {
-        consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
+        tokenizer.consume(":");  // required
+        consumeFieldValues(tokenizer, extensionRegistry, target, field,
+            extension, parseTreeBuilder, unknownFields);
+      }
+
+      if (parseTreeBuilder != null) {
+        parseTreeBuilder.setLocation(
+            field, TextFormatParseLocation.create(startLine, startColumn));
       }
 
       // For historical reasons, fields may optionally be separated by commas or
@@ -1498,6 +1617,45 @@
     }
 
     /**
+     * Parse a one or more field values from {@code tokenizer} and merge it into
+     * {@code builder}.
+     */
+    private void consumeFieldValues(
+        final Tokenizer tokenizer,
+        final ExtensionRegistry extensionRegistry,
+        final MessageReflection.MergeTarget target,
+        final FieldDescriptor field,
+        final ExtensionRegistry.ExtensionInfo extension,
+        final TextFormatParseInfoTree.Builder parseTreeBuilder,
+        List<String> unknownFields)
+        throws ParseException {
+      // Support specifying repeated field values as a comma-separated list.
+      // Ex."foo: [1, 2, 3]"
+      if (field.isRepeated() && tokenizer.tryConsume("[")) {
+        if (!tokenizer.tryConsume("]")) {  // Allow "foo: []" to be treated as empty.
+          while (true) {
+            consumeFieldValue(
+                tokenizer,
+                extensionRegistry,
+                target,
+                field,
+                extension,
+                parseTreeBuilder,
+                unknownFields);
+            if (tokenizer.tryConsume("]")) {
+              // End of list.
+              break;
+            }
+            tokenizer.consume(",");
+          }
+        }
+      } else {
+        consumeFieldValue(tokenizer, extensionRegistry, target, field,
+            extension, parseTreeBuilder, unknownFields);
+      }
+    }
+
+    /**
      * Parse a single field value from {@code tokenizer} and merge it into
      * {@code builder}.
      */
@@ -1506,7 +1664,9 @@
         final ExtensionRegistry extensionRegistry,
         final MessageReflection.MergeTarget target,
         final FieldDescriptor field,
-        final ExtensionRegistry.ExtensionInfo extension)
+        final ExtensionRegistry.ExtensionInfo extension,
+        final TextFormatParseInfoTree.Builder parseTreeBuilder,
+        List<String> unknownFields)
         throws ParseException {
       Object value = null;
 
@@ -1528,7 +1688,8 @@
             throw tokenizer.parseException(
               "Expected \"" + endToken + "\".");
           }
-          mergeField(tokenizer, extensionRegistry, subField);
+          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder,
+              unknownFields);
         }
 
         value = subField.finish();
@@ -1584,17 +1745,40 @@
               final int number = tokenizer.consumeInt32();
               value = enumType.findValueByNumber(number);
               if (value == null) {
-                throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName()
-                  + "\" has no value with number " + number + '.');
+                String unknownValueMsg =
+                    "Enum type \""
+                        + enumType.getFullName()
+                        + "\" has no value with number "
+                        + number
+                        + '.';
+                if (allowUnknownEnumValues) {
+                  logger.warning(unknownValueMsg);
+                  return;
+                } else {
+                  throw tokenizer.parseExceptionPreviousToken(
+                      "Enum type \""
+                          + enumType.getFullName()
+                          + "\" has no value with number "
+                          + number
+                          + '.');
+                }
               }
             } else {
               final String id = tokenizer.consumeIdentifier();
               value = enumType.findValueByName(id);
               if (value == null) {
-                throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName()
-                  + "\" has no value named \"" + id + "\".");
+                String unknownValueMsg =
+                    "Enum type \""
+                        + enumType.getFullName()
+                        + "\" has no value named \""
+                        + id
+                        + "\".";
+                if (allowUnknownEnumValues) {
+                  logger.warning(unknownValueMsg);
+                  return;
+                } else {
+                  throw tokenizer.parseExceptionPreviousToken(unknownValueMsg);
+                }
               }
             }
 
@@ -1607,6 +1791,8 @@
       }
 
       if (field.isRepeated()) {
+        // TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
+        //     check for duplicate map keys here.
         target.addRepeatedField(field, value);
       } else if ((singularOverwritePolicy
               == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
@@ -1704,11 +1890,6 @@
   // Some of these methods are package-private because Descriptors.java uses
   // them.
 
-  private interface ByteSequence {
-    int size();
-    byte byteAt(int offset);
-  }
-
   /**
    * Escapes bytes in the format used in protocol buffer text format, which
    * is the same as the format used for C string literals.  All bytes
@@ -1717,74 +1898,15 @@
    * which no defined short-hand escape sequence is defined will be escaped
    * using 3-digit octal sequences.
    */
-  public static String escapeBytes(final ByteSequence input) {
-    final StringBuilder builder = new StringBuilder(input.size());
-    for (int i = 0; i < input.size(); i++) {
-      final byte b = input.byteAt(i);
-      switch (b) {
-        // Java does not recognize \a or \v, apparently.
-        case 0x07: builder.append("\\a"); break;
-        case '\b': builder.append("\\b"); break;
-        case '\f': builder.append("\\f"); break;
-        case '\n': builder.append("\\n"); break;
-        case '\r': builder.append("\\r"); break;
-        case '\t': builder.append("\\t"); break;
-        case 0x0b: builder.append("\\v"); break;
-        case '\\': builder.append("\\\\"); break;
-        case '\'': builder.append("\\\'"); break;
-        case '"' : builder.append("\\\""); break;
-        default:
-          // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
-          // printable.  Other byte values must be escaped.
-          if (b >= 0x20 && b <= 0x7e) {
-            builder.append((char) b);
-          } else {
-            builder.append('\\');
-            builder.append((char) ('0' + ((b >>> 6) & 3)));
-            builder.append((char) ('0' + ((b >>> 3) & 7)));
-            builder.append((char) ('0' + (b & 7)));
-          }
-          break;
-      }
-    }
-    return builder.toString();
-  }
-
-  /**
-   * Escapes bytes in the format used in protocol buffer text format, which
-   * is the same as the format used for C string literals.  All bytes
-   * that are not printable 7-bit ASCII characters are escaped, as well as
-   * backslash, single-quote, and double-quote characters.  Characters for
-   * which no defined short-hand escape sequence is defined will be escaped
-   * using 3-digit octal sequences.
-   */
-  public static String escapeBytes(final ByteString input) {
-    return escapeBytes(new ByteSequence() {
-      @Override
-      public int size() {
-        return input.size();
-      }
-      @Override
-      public byte byteAt(int offset) {
-        return input.byteAt(offset);
-      }
-    });
+  public static String escapeBytes(ByteString input) {
+    return TextFormatEscaper.escapeBytes(input);
   }
 
   /**
    * Like {@link #escapeBytes(ByteString)}, but used for byte array.
    */
-  public static String escapeBytes(final byte[] input) {
-    return escapeBytes(new ByteSequence() {
-      @Override
-      public int size() {
-        return input.length;
-      }
-      @Override
-      public byte byteAt(int offset) {
-        return input[offset];
-      }
-    });
+  public static String escapeBytes(byte[] input) {
+    return TextFormatEscaper.escapeBytes(input);
   }
 
   /**
@@ -1868,7 +1990,9 @@
       }
     }
 
-    return ByteString.copyFrom(result, 0, pos);
+    return result.length == pos
+        ? ByteString.wrap(result)  // This reference has not been out of our control.
+        : ByteString.copyFrom(result, 0, pos);
   }
 
   /**
@@ -1896,7 +2020,7 @@
    * Escape double quotes and backslashes in a String for unicode output of a message.
    */
   public static String escapeDoubleQuotesAndBackslashes(final String input) {
-    return input.replace("\\", "\\\\").replace("\"", "\\\"");
+    return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input);
   }
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
index e69de29..da9cead 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
@@ -0,0 +1,137 @@
+// 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;
+
+/**
+ * Provide text format escaping support for proto2 instances.
+ */
+final class TextFormatEscaper {
+  private TextFormatEscaper() {}
+
+  private interface ByteSequence {
+    int size();
+    byte byteAt(int offset);
+  }
+
+  /**
+   * Escapes bytes in the format used in protocol buffer text format, which
+   * is the same as the format used for C string literals.  All bytes
+   * that are not printable 7-bit ASCII characters are escaped, as well as
+   * backslash, single-quote, and double-quote characters.  Characters for
+   * which no defined short-hand escape sequence is defined will be escaped
+   * using 3-digit octal sequences.
+   */
+  static String escapeBytes(final ByteSequence input) {
+    final StringBuilder builder = new StringBuilder(input.size());
+    for (int i = 0; i < input.size(); i++) {
+      final byte b = input.byteAt(i);
+      switch (b) {
+        // Java does not recognize \a or \v, apparently.
+        case 0x07: builder.append("\\a"); break;
+        case '\b': builder.append("\\b"); break;
+        case '\f': builder.append("\\f"); break;
+        case '\n': builder.append("\\n"); break;
+        case '\r': builder.append("\\r"); break;
+        case '\t': builder.append("\\t"); break;
+        case 0x0b: builder.append("\\v"); break;
+        case '\\': builder.append("\\\\"); break;
+        case '\'': builder.append("\\\'"); break;
+        case '"' : builder.append("\\\""); break;
+        default:
+          // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
+          // printable.  Other byte values must be escaped.
+          if (b >= 0x20 && b <= 0x7e) {
+            builder.append((char) b);
+          } else {
+            builder.append('\\');
+            builder.append((char) ('0' + ((b >>> 6) & 3)));
+            builder.append((char) ('0' + ((b >>> 3) & 7)));
+            builder.append((char) ('0' + (b & 7)));
+          }
+          break;
+      }
+    }
+    return builder.toString();
+  }
+
+  /**
+   * Escapes bytes in the format used in protocol buffer text format, which
+   * is the same as the format used for C string literals.  All bytes
+   * that are not printable 7-bit ASCII characters are escaped, as well as
+   * backslash, single-quote, and double-quote characters.  Characters for
+   * which no defined short-hand escape sequence is defined will be escaped
+   * using 3-digit octal sequences.
+   */
+  static String escapeBytes(final ByteString input) {
+    return escapeBytes(new ByteSequence() {
+      @Override
+      public int size() {
+        return input.size();
+      }
+      @Override
+      public byte byteAt(int offset) {
+        return input.byteAt(offset);
+      }
+    });
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but used for byte array.
+   */
+  static String escapeBytes(final byte[] input) {
+    return escapeBytes(new ByteSequence() {
+      @Override
+      public int size() {
+        return input.length;
+      }
+      @Override
+      public byte byteAt(int offset) {
+        return input[offset];
+      }
+    });
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+   * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+   * individually as a 3-digit octal escape.  Yes, it's weird.
+   */
+  static String escapeText(final String input) {
+    return escapeBytes(ByteString.copyFromUtf8(input));
+  }
+
+  /**
+   * Escape double quotes and backslashes in a String for unicode output of a message.
+   */
+  static String escapeDoubleQuotesAndBackslashes(final String input) {
+    return input.replace("\\", "\\\\").replace("\"", "\\\"");
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
new file mode 100644
index 0000000..0127ce9
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
@@ -0,0 +1,226 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * Data structure which is populated with the locations of each field value parsed from the text.
+ *
+ * <p>The locations of primary fields values are retrieved by {@code getLocation} or
+ * {@code getLocations}.  The locations of sub message values are within nested
+ * {@code TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or
+ * {@code getNestedTrees}.
+ *
+ * <p>The {@code TextFormatParseInfoTree} is created by a Builder.
+ */
+public class TextFormatParseInfoTree {
+
+  // Defines a mapping between each field's descriptor to the list of locations where
+  // its value(s) were was encountered.
+  private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+  // Defines a mapping between a field's descriptor to a list of TextFormatParseInfoTrees for
+  // sub message location information.
+  Map<FieldDescriptor, List<TextFormatParseInfoTree>> subtreesFromField;
+
+  /**
+   * Construct a {@code TextFormatParseInfoTree}.
+   *
+   * @param locationsFromField a map of fields to location in the source code
+   * @param subtreeBuildersFromField a map of fields to parse tree location information builders
+   */
+  private TextFormatParseInfoTree(
+      Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField,
+      Map<FieldDescriptor, List<TextFormatParseInfoTree.Builder>> subtreeBuildersFromField) {
+
+    // The maps are unmodifiable.  The values in the maps are unmodifiable.
+    Map<FieldDescriptor, List<TextFormatParseLocation>> locs =
+        new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+    for (Entry<FieldDescriptor, List<TextFormatParseLocation>> kv : locationsFromField.entrySet()) {
+      locs.put(kv.getKey(), Collections.unmodifiableList(kv.getValue()));
+    }
+    this.locationsFromField = Collections.unmodifiableMap(locs);
+
+    Map<FieldDescriptor, List<TextFormatParseInfoTree>> subs =
+        new HashMap<FieldDescriptor, List<TextFormatParseInfoTree>>();
+    for (Entry<FieldDescriptor, List<Builder>> kv : subtreeBuildersFromField.entrySet()) {
+      List<TextFormatParseInfoTree> submessagesOfField = new ArrayList<TextFormatParseInfoTree>();
+      for (Builder subBuilder : kv.getValue()) {
+        submessagesOfField.add(subBuilder.build());
+      }
+      subs.put(kv.getKey(), Collections.unmodifiableList(submessagesOfField));
+    }
+    this.subtreesFromField = Collections.unmodifiableMap(subs);
+  }
+
+ /**
+  * Retrieve all the locations of a field.
+  *
+  * @param fieldDescriptor the the @{link FieldDescriptor} of the desired field
+  * @return a list of the locations of values of the field.  If there are not values
+  *         or the field doesn't exist, an empty list is returned.
+  */
+  public List<TextFormatParseLocation> getLocations(final FieldDescriptor fieldDescriptor) {
+    List<TextFormatParseLocation> result = locationsFromField.get(fieldDescriptor);
+    return (result == null) ? Collections.<TextFormatParseLocation>emptyList() : result;
+  }
+
+  /**
+   * Get the location in the source of a field's value.
+   *
+   * <p>Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed
+   * text.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+   * @param index the index of the value.
+   * @return the {@link TextFormatParseLocation} of the value
+   * @throws IllegalArgumentException index is out of range
+   */
+  public TextFormatParseLocation getLocation(final FieldDescriptor fieldDescriptor, int index) {
+    return getFromList(getLocations(fieldDescriptor), index, fieldDescriptor);
+  }
+
+  /**
+   * Retrieve a list of all the location information trees for a sub message field.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+   * @return A list of {@link TextFormatParseInfoTree}
+   */
+  public List<TextFormatParseInfoTree> getNestedTrees(final FieldDescriptor fieldDescriptor) {
+    List<TextFormatParseInfoTree> result = subtreesFromField.get(fieldDescriptor);
+    return result == null ? Collections.<TextFormatParseInfoTree>emptyList() : result;
+  }
+
+  /**
+   * Returns the parse info tree for the given field, which must be a message type.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message
+   * @param index the index of message value.
+   * @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field
+   *         doesn't exist or the index is out of range.
+   * @throws IllegalArgumentException if index is out of range
+   */
+  public TextFormatParseInfoTree getNestedTree(final FieldDescriptor fieldDescriptor, int index) {
+    return getFromList(getNestedTrees(fieldDescriptor), index, fieldDescriptor);
+  }
+
+  /**
+   * Create a builder for a {@code ParseInfoTree}.
+   *
+   * @return the builder
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private static <T> T getFromList(List<T> list, int index, FieldDescriptor fieldDescriptor) {
+    if (index >= list.size() || index < 0)  {
+      throw new IllegalArgumentException(String.format("Illegal index field: %s, index %d",
+          fieldDescriptor == null ? "<null>" : fieldDescriptor.getName(), index));
+    }
+    return list.get(index);
+  }
+
+  /**
+   * Builder for a {@link TextFormatParseInfoTree}.
+   */
+  public static class Builder {
+
+    private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+    // Defines a mapping between a field's descriptor to a list of ParseInfoTrees builders for
+    // sub message location information.
+    private Map<FieldDescriptor, List<Builder>> subtreeBuildersFromField;
+
+     /**
+     * Create a root level {@ParseInfoTree} builder.
+     */
+    private Builder() {
+      locationsFromField = new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+      subtreeBuildersFromField = new HashMap<FieldDescriptor, List<Builder>>();
+    }
+
+    /**
+     * Record the starting location of a single value for a field.
+     *
+     * @param fieldDescriptor the field
+     * @param location source code location information
+     */
+    public Builder setLocation(
+        final FieldDescriptor fieldDescriptor, TextFormatParseLocation location) {
+      List<TextFormatParseLocation> fieldLocations = locationsFromField.get(fieldDescriptor);
+      if (fieldLocations == null) {
+        fieldLocations = new ArrayList<TextFormatParseLocation>();
+        locationsFromField.put(fieldDescriptor, fieldLocations);
+      }
+      fieldLocations.add(location);
+      return this;
+    }
+
+    /**
+     * Set for a sub message.
+     *
+     * <p>A new builder is created for a sub message. The builder that is returned is a new builder.
+     * The return is <em>not</em> the invoked {@code builder.getBuilderForSubMessageField}.
+     *
+     * @param fieldDescriptor the field whose value is the submessage
+     * @return a new Builder for the sub message
+     */
+    public Builder getBuilderForSubMessageField(final FieldDescriptor fieldDescriptor) {
+      List<Builder> submessageBuilders = subtreeBuildersFromField.get(fieldDescriptor);
+      if (submessageBuilders == null) {
+        submessageBuilders = new ArrayList<Builder>();
+        subtreeBuildersFromField.put(fieldDescriptor, submessageBuilders);
+      }
+      Builder subtreeBuilder = new Builder();
+      submessageBuilders.add(subtreeBuilder);
+      return subtreeBuilder;
+    }
+
+    /**
+     * Build the {@code TextFormatParseInfoTree}.
+     *
+     * @return the {@code TextFormatParseInfoTree}
+     */
+    public TextFormatParseInfoTree build() {
+      return new TextFormatParseInfoTree(locationsFromField, subtreeBuildersFromField);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
new file mode 100644
index 0000000..cce286e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
@@ -0,0 +1,104 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.Arrays;
+
+/**
+ * A location in the source code.
+ *
+ * <p>A location is the starting line number and starting column number.
+ */
+public final class TextFormatParseLocation {
+
+  /**
+   * The empty location.
+   */
+  public static final TextFormatParseLocation EMPTY = new TextFormatParseLocation(-1, -1);
+
+  /**
+   * Create a location.
+   *
+   * @param line the starting line number
+   * @param column the starting column number
+   * @return a {@code ParseLocation}
+   */
+  static TextFormatParseLocation create(int line, int column) {
+    if (line == -1 && column == -1) {
+      return EMPTY;
+    }
+    if (line < 0 || column < 0) {
+      throw new IllegalArgumentException(
+          String.format("line and column values must be >= 0: line %d, column: %d", line, column));
+    }
+    return new TextFormatParseLocation(line, column);
+  }
+
+  private final int line;
+  private final int column;
+
+  private TextFormatParseLocation(int line, int column) {
+    this.line = line;
+    this.column = column;
+  }
+
+  public int getLine() {
+    return line;
+  }
+
+  public int getColumn() {
+    return column;
+  }
+
+  @Override
+  public String toString() {
+    return String.format("ParseLocation{line=%d, column=%d}", line, column);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof TextFormatParseLocation)) {
+      return false;
+    }
+    TextFormatParseLocation that = (TextFormatParseLocation) o;
+    return (this.line == that.getLine())
+         && (this.column == that.getColumn());
+  }
+
+  @Override
+  public int hashCode() {
+    int[] values = {line, column};
+    return Arrays.hashCode(values);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
index 7cd2250..37d6463 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -31,7 +31,6 @@
 package com.google.protobuf;
 
 import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -39,6 +38,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.TreeMap;
 
@@ -57,7 +57,10 @@
  * @author kenton@google.com Kenton Varda
  */
 public final class UnknownFieldSet implements MessageLite {
-  private UnknownFieldSet() {}
+
+  private UnknownFieldSet() {
+    fields = null;
+  }
 
   /** Create a new {@link Builder}. */
   public static Builder newBuilder() {
@@ -76,20 +79,23 @@
   public static UnknownFieldSet getDefaultInstance() {
     return defaultInstance;
   }
+  @Override
   public UnknownFieldSet getDefaultInstanceForType() {
     return defaultInstance;
   }
   private static final UnknownFieldSet defaultInstance =
-    new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
+    new UnknownFieldSet(Collections.<Integer, Field>emptyMap(),
+        Collections.<Integer, Field>emptyMap());
 
   /**
    * Construct an {@code UnknownFieldSet} around the given map.  The map is
    * expected to be immutable.
    */
-  private UnknownFieldSet(final Map<Integer, Field> fields) {
+  UnknownFieldSet(final Map<Integer, Field> fields,
+      final Map<Integer, Field> fieldsDescending) {
     this.fields = fields;
   }
-  private Map<Integer, Field> fields;
+  private final Map<Integer, Field> fields;
 
 
   @Override
@@ -126,9 +132,11 @@
   }
 
   /** Serializes the set and writes it to {@code output}. */
+  @Override
   public void writeTo(final CodedOutputStream output) throws IOException {
     for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      entry.getValue().writeTo(entry.getKey(), output);
+      Field field = entry.getValue();
+      field.writeTo(entry.getKey(), output);
     }
   }
 
@@ -146,6 +154,7 @@
    * Serializes the message to a {@code ByteString} and returns it. This is
    * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
    */
+  @Override
   public ByteString toByteString() {
     try {
       final ByteString.CodedBuilder out =
@@ -163,6 +172,7 @@
    * Serializes the message to a {@code byte} array and returns it.  This is
    * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
    */
+  @Override
   public byte[] toByteArray() {
     try {
       final byte[] result = new byte[getSerializedSize()];
@@ -181,12 +191,14 @@
    * Serializes the message and writes it to {@code output}.  This is just a
    * trivial wrapper around {@link #writeTo(CodedOutputStream)}.
    */
+  @Override
   public void writeTo(final OutputStream output) throws IOException {
     final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
     writeTo(codedOutput);
     codedOutput.flush();
   }
 
+  @Override
   public void writeDelimitedTo(OutputStream output) throws IOException {
     final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
     codedOutput.writeRawVarint32(getSerializedSize());
@@ -195,6 +207,7 @@
   }
 
   /** Get the number of bytes required to encode this set. */
+  @Override
   public int getSerializedSize() {
     int result = 0;
     for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
@@ -215,10 +228,8 @@
     }
   }
 
-  /**
-   * Get the number of bytes required to encode this set using
-   * {@code MessageSet} wire format.
-   */
+
+  /** Get the number of bytes required to encode this set using {@code MessageSet} wire format. */
   public int getSerializedSizeAsMessageSet() {
     int result = 0;
     for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
@@ -228,6 +239,7 @@
     return result;
   }
 
+  @Override
   public boolean isInitialized() {
     // UnknownFieldSets do not have required fields, so they are always
     // initialized.
@@ -258,10 +270,12 @@
     return newBuilder().mergeFrom(input).build();
   }
 
+  @Override
   public Builder newBuilderForType() {
     return newBuilder();
   }
 
+  @Override
   public Builder toBuilder() {
     return newBuilder().mergeFrom(this);
   }
@@ -329,18 +343,21 @@
      * in undefined behavior and can cause a {@code NullPointerException} to be
      * thrown.
      */
+    @Override
     public UnknownFieldSet build() {
-      getFieldBuilder(0);  // Force lastField to be built.
+      getFieldBuilder(0); // Force lastField to be built.
       final UnknownFieldSet result;
       if (fields.isEmpty()) {
         result = getDefaultInstance();
       } else {
-        result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
+        Map<Integer, Field> descendingFields = null;
+        result = new UnknownFieldSet(Collections.unmodifiableMap(fields), descendingFields);
       }
       fields = null;
       return result;
     }
 
+    @Override
     public UnknownFieldSet buildPartial() {
       // No required fields, so this is the same as build().
       return build();
@@ -349,10 +366,12 @@
     @Override
     public Builder clone() {
       getFieldBuilder(0);  // Force lastField to be built.
+      Map<Integer, Field> descendingFields = null;
       return UnknownFieldSet.newBuilder().mergeFrom(
-          new UnknownFieldSet(fields));
+          new UnknownFieldSet(fields, descendingFields));
     }
 
+    @Override
     public UnknownFieldSet getDefaultInstanceForType() {
       return UnknownFieldSet.getDefaultInstance();
     }
@@ -364,6 +383,7 @@
     }
 
     /** Reset the builder to an empty set. */
+    @Override
     public Builder clear() {
       reinitialize();
       return this;
@@ -487,6 +507,7 @@
      * Parse an entire message from {@code input} and merge its fields into
      * this set.
      */
+    @Override
     public Builder mergeFrom(final CodedInputStream input) throws IOException {
       while (true) {
         final int tag = input.readTag();
@@ -536,8 +557,8 @@
      * set being built.  This is just a small wrapper around
      * {@link #mergeFrom(CodedInputStream)}.
      */
-    public Builder mergeFrom(final ByteString data)
-        throws InvalidProtocolBufferException {
+    @Override
+    public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input = data.newCodedInput();
         mergeFrom(input);
@@ -557,8 +578,8 @@
      * set being built.  This is just a small wrapper around
      * {@link #mergeFrom(CodedInputStream)}.
      */
-    public Builder mergeFrom(final byte[] data)
-        throws InvalidProtocolBufferException {
+    @Override
+    public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input = CodedInputStream.newInstance(data);
         mergeFrom(input);
@@ -578,6 +599,7 @@
      * set being built.  This is just a small wrapper around
      * {@link #mergeFrom(CodedInputStream)}.
      */
+    @Override
     public Builder mergeFrom(final InputStream input) throws IOException {
       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
       mergeFrom(codedInput);
@@ -585,8 +607,8 @@
       return this;
     }
 
-    public boolean mergeDelimitedFrom(InputStream input)
-        throws IOException {
+    @Override
+    public boolean mergeDelimitedFrom(InputStream input) throws IOException {
       final int firstByte = input.read();
       if (firstByte == -1) {
         return false;
@@ -597,30 +619,29 @@
       return true;
     }
 
-    public boolean mergeDelimitedFrom(
-        InputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
+    @Override
+    public boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
       // UnknownFieldSet has no extensions.
       return mergeDelimitedFrom(input);
     }
 
-    public Builder mergeFrom(
-        CodedInputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
+    @Override
+    public Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
       // UnknownFieldSet has no extensions.
       return mergeFrom(input);
     }
 
-    public Builder mergeFrom(
-        ByteString data,
-        ExtensionRegistryLite extensionRegistry)
+    @Override
+    public Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       // UnknownFieldSet has no extensions.
       return mergeFrom(data);
     }
 
-    public Builder mergeFrom(byte[] data, int off, int len)
-        throws InvalidProtocolBufferException {
+    @Override
+    public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException {
       try {
         final CodedInputStream input =
             CodedInputStream.newInstance(data, off, len);
@@ -636,29 +657,37 @@
       }
     }
 
-    public Builder mergeFrom(
-        byte[] data,
-        ExtensionRegistryLite extensionRegistry)
+    @Override
+    public Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       // UnknownFieldSet has no extensions.
       return mergeFrom(data);
     }
 
-    public Builder mergeFrom(
-        byte[] data, int off, int len,
-        ExtensionRegistryLite extensionRegistry)
+    @Override
+    public Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       // UnknownFieldSet has no extensions.
       return mergeFrom(data, off, len);
     }
 
-    public Builder mergeFrom(
-        InputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
+    @Override
+    public Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
       // UnknownFieldSet has no extensions.
       return mergeFrom(input);
     }
 
+    @Override
+    public Builder mergeFrom(MessageLite m) {
+      if (m instanceof UnknownFieldSet) {
+        return mergeFrom((UnknownFieldSet) m);
+      }
+      throw new IllegalArgumentException(
+          "mergeFrom(MessageLite) can only merge messages of the same type.");
+    }
+
+    @Override
     public boolean isInitialized() {
       // UnknownFieldSets do not have required fields, so they are always
       // initialized.
@@ -816,9 +845,10 @@
       }
     }
 
+
     /**
-     * Get the number of bytes required to encode this field, including field
-     * number, using {@code MessageSet} wire format.
+     * Get the number of bytes required to encode this field, including field number, using {@code
+     * MessageSet} wire format.
      */
     public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
       int result = 0;
@@ -987,6 +1017,7 @@
    * Parser to implement MessageLite interface.
    */
   public static final class Parser extends AbstractParser<UnknownFieldSet> {
+    @Override
     public UnknownFieldSet parsePartialFrom(
         CodedInputStream input, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
@@ -996,7 +1027,7 @@
       } catch (InvalidProtocolBufferException e) {
         throw e.setUnfinishedMessage(builder.buildPartial());
       } catch (IOException e) {
-        throw new InvalidProtocolBufferException(e.getMessage())
+        throw new InvalidProtocolBufferException(e)
             .setUnfinishedMessage(builder.buildPartial());
       }
       return builder.buildPartial();
@@ -1004,6 +1035,7 @@
   }
 
   private static final Parser PARSER = new Parser();
+  @Override
   public final Parser getParserForType() {
     return PARSER;
   }
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
index 435ad4d..f0b919a 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -61,15 +61,6 @@
   public static UnknownFieldSetLite getDefaultInstance() {
     return DEFAULT_INSTANCE;
   }
-
-  /**
-   * Returns an empty {@code UnknownFieldSetLite.Builder}.
-   *
-   * <p>For use by generated code only.
-   */
-  public static Builder newBuilder() {
-    return new Builder();
-  }
   
   /**
    * Returns a new mutable instance.
@@ -90,7 +81,7 @@
     System.arraycopy(second.objects, 0, objects, first.count, second.count);
     return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
   }
-  
+
   /**
    * The number of elements in the set.
    */
@@ -185,6 +176,42 @@
   }
 
   /**
+   * Serializes the set and writes it to {@code output} using {@code MessageSet} wire format.
+   *
+   * <p>For use by generated code only.
+   */
+  public void writeAsMessageSetTo(CodedOutputStream output) throws IOException {
+    for (int i = 0; i < count; i++) {
+      int fieldNumber = WireFormat.getTagFieldNumber(tags[i]);
+      output.writeRawMessageSetExtension(fieldNumber, (ByteString) objects[i]);
+    }
+  }
+
+
+  /**
+   * Get the number of bytes required to encode this field, including field number, using {@code
+   * MessageSet} wire format.
+   */
+  public int getSerializedSizeAsMessageSet() {
+    int size = memoizedSerializedSize;
+    if (size != -1) {
+      return size;
+    }
+    
+    size = 0;
+    for (int i = 0; i < count; i++) {
+      int tag = tags[i];
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+      size += CodedOutputStream.computeRawMessageSetExtensionSize(
+          fieldNumber, (ByteString) objects[i]);
+    }
+    
+    memoizedSerializedSize = size;
+    
+    return size;
+  }
+
+  /**
    * Get the number of bytes required to encode this set.
    *
    * <p>For use by generated code only.
@@ -225,6 +252,24 @@
     
     return size;
   }
+  
+  private static boolean equals(int[] tags1, int[] tags2, int count) {
+    for (int i = 0; i < count; ++i) {
+      if (tags1[i] != tags2[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static boolean equals(Object[] objects1, Object[] objects2, int count) {
+    for (int i = 0; i < count; ++i) {
+      if (!objects1[i].equals(objects2[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
 
   @Override
   public boolean equals(Object obj) {
@@ -242,27 +287,59 @@
     
     UnknownFieldSetLite other = (UnknownFieldSetLite) obj;    
     if (count != other.count
-        // TODO(dweis): Only have to compare up to count but at worst 2x worse than we need to do.
-        || !Arrays.equals(tags, other.tags)
-        || !Arrays.deepEquals(objects, other.objects)) {
+        || !equals(tags, other.tags, count)
+        || !equals(objects, other.objects, count)) {
       return false;
     }
 
     return true;
   }
 
-  @Override
-  public int hashCode() {
+  private static int hashCode(int[] tags, int count) {
     int hashCode = 17;
-    
-    hashCode = 31 * hashCode + count;
-    hashCode = 31 * hashCode + Arrays.hashCode(tags);
-    hashCode = 31 * hashCode + Arrays.deepHashCode(objects);
-    
+    for (int i = 0; i < count; ++i) {
+      hashCode = 31 * hashCode + tags[i];
+    }
     return hashCode;
   }
 
-  private void storeField(int tag, Object value) {
+  private static int hashCode(Object[] objects, int count) {
+    int hashCode = 17;
+    for (int i = 0; i < count; ++i) {
+      hashCode = 31 * hashCode + objects[i].hashCode();
+    }
+    return hashCode;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 17;
+
+    hashCode = 31 * hashCode + count;
+    hashCode = 31 * hashCode + hashCode(tags, count);
+    hashCode = 31 * hashCode + hashCode(objects, count);
+
+    return hashCode;
+  }
+
+  /**
+   * Prints a String representation of the unknown field set.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces the fields should be indented by
+   */
+  final void printWithIndent(StringBuilder buffer, int indent) {
+    for (int i = 0; i < count; i++) {
+      int fieldNumber = WireFormat.getTagFieldNumber(tags[i]);
+      MessageLiteToString.printField(buffer, indent, String.valueOf(fieldNumber), objects[i]);
+    }
+  }
+
+  // Package private for unsafe experimental runtime.
+  void storeField(int tag, Object value) {
+    checkMutable();
     ensureCapacity();
     
     tags[count] = tag;
@@ -369,90 +446,4 @@
     }
     return this;
   }
-  
-  /**
-   * Builder for {@link UnknownFieldSetLite}s.
-   *
-   * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
-   *
-   * <p>For use by generated code only.
-   */
-  // TODO(dweis): Update the mutable API to no longer need this builder and delete.
-  public static final class Builder {
-
-    private UnknownFieldSetLite set;
-    
-    private Builder() {
-      this.set = null;
-    }
-
-    /**
-     * Ensures internal state is initialized for use.
-     */
-    private void ensureNotBuilt() {
-      if (set == null) {
-        set = new UnknownFieldSetLite();
-      }
-      
-      set.checkMutable();
-    }
-    
-    /**
-     * Parse a single field from {@code input} and merge it into this set.
-     *
-     * <p>For use by generated code only.
-     *
-     * @param tag The field's tag number, which was already parsed.
-     * @return {@code false} if the tag is an end group tag.
-     */
-    boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
-      ensureNotBuilt();
-      return set.mergeFieldFrom(tag, input);
-    }
-
-    /**
-     * Convenience method for merging a new field containing a single varint
-     * value. This is used in particular when an unknown enum value is
-     * encountered.
-     *
-     * <p>For use by generated code only.
-     */
-    Builder mergeVarintField(int fieldNumber, int value) {
-      ensureNotBuilt();
-      set.mergeVarintField(fieldNumber, value);
-      return this;
-    }
-    
-    /**
-     * Convenience method for merging a length-delimited field.
-     *
-     * <p>For use by generated code only.
-     */
-    public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
-      ensureNotBuilt();  
-      set.mergeLengthDelimitedField(fieldNumber, value);
-      return this;
-    }
-    
-    /**
-     * Build the {@link UnknownFieldSetLite} and return it.
-     *
-     * <p>Once {@code build()} has been called, the {@code Builder} will no
-     * longer be usable.  Calling any method after {@code build()} will result
-     * in undefined behavior and can cause an
-     * {@code UnsupportedOperationException} to be thrown.
-     *
-     * <p>For use by generated code only.
-     */
-    public UnknownFieldSetLite build() {
-      if (set == null) {
-        return DEFAULT_INSTANCE;
-      }
-      
-      set.checkMutable();
-      set.makeImmutable();
-
-      return set;
-    }
-  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
index 5257c5a..30e8791 100644
--- a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
+++ b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
@@ -68,42 +68,42 @@
     return list.size();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public ByteString getByteString(int index) {
     return list.getByteString(index);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void add(ByteString element) {
     throw new UnsupportedOperationException();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void set(int index, ByteString element) {
     throw new UnsupportedOperationException();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public boolean addAllByteString(Collection<? extends ByteString> element) {
     throw new UnsupportedOperationException();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public byte[] getByteArray(int index) {
     return list.getByteArray(index);
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void add(byte[] element) {
     throw new UnsupportedOperationException();
   }
   
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void set(int index, byte[] element) {
     throw new UnsupportedOperationException();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public boolean addAllByteArray(Collection<byte[]> element) {
     throw new UnsupportedOperationException();
   }
@@ -113,47 +113,47 @@
     return new ListIterator<String>() {
       ListIterator<String> iter = list.listIterator(index);
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public boolean hasNext() {
         return iter.hasNext();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public String next() {
         return iter.next();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public boolean hasPrevious() {
         return iter.hasPrevious();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public String previous() {
         return iter.previous();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public int nextIndex() {
         return iter.nextIndex();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public int previousIndex() {
         return iter.previousIndex();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public void remove() {
         throw new UnsupportedOperationException();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public void set(String o) {
         throw new UnsupportedOperationException();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public void add(String o) {
         throw new UnsupportedOperationException();
       }
@@ -165,45 +165,45 @@
     return new Iterator<String>() {
       Iterator<String> iter = list.iterator();
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public boolean hasNext() {
         return iter.hasNext();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public String next() {
         return iter.next();
       }
 
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
+      @Override
       public void remove() {
         throw new UnsupportedOperationException();
       }
     };
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public List<?> getUnderlyingElements() {
     // The returned value is already unmodifiable.
     return list.getUnderlyingElements();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void mergeFrom(LazyStringList other) {
     throw new UnsupportedOperationException();
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public List<byte[]> asByteArrayList() {
     return Collections.unmodifiableList(list.asByteArrayList());
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public List<ByteString> asByteStringList() {
     return Collections.unmodifiableList(list.asByteStringList());
   }
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public LazyStringList getUnmodifiableView() {
     return this;
   }
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
index f443ee3..878c775 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 
 /**
@@ -41,6 +42,23 @@
  * guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a
  * {@link ByteString} can lead to unexpected and undesirable consequences in your application,
  * and will likely be difficult to debug. Proceed with caution!
+ *
+ * <p>This can have a number of significant side affects that have
+ * spooky-action-at-a-distance-like behavior. In particular, if the bytes value changes out from
+ * under a Protocol Buffer:
+ * <ul>
+ * <li>serialization may throw
+ * <li>serialization may succeed but the wrong bytes may be written out
+ * <li>messages are no longer threadsafe
+ * <li>hashCode may be incorrect
+ *   <ul>
+ *   <li>can result in a permanent memory leak when used as a key in a long-lived HashMap
+ *   <li> the semantics of many programs may be violated if this is the case
+ *   </ul>
+ * </ul>
+ * Each of these issues will occur in parts of the code base that are entirely distinct from the
+ * parts of the code base modifying the buffer. In fact, both parts of the code base may be correct
+ * - it is the bridging with the unsafe operations that was in error!
  */
 @ExperimentalApi
 public final class UnsafeByteOperations {
@@ -49,15 +67,54 @@
   /**
    * An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
    *
-   * @param buffer the Java NIO buffer to be wrapped.
-   * @return a {@link ByteString} backed by the provided buffer.
+   * @param buffer the buffer to be wrapped
+   * @return a {@link ByteString} backed by the provided buffer
+   */
+  public static ByteString unsafeWrap(byte[] buffer) {
+    return ByteString.wrap(buffer);
+  }
+
+  /**
+   * An unsafe operation that returns a {@link ByteString} that is backed by a subregion of the
+   * provided buffer.
+   *
+   * @param buffer the buffer to be wrapped
+   * @param offset the offset of the wrapped region
+   * @param length the number of bytes of the wrapped region
+   * @return a {@link ByteString} backed by the provided buffer
+   */
+  public static ByteString unsafeWrap(byte[] buffer, int offset, int length) {
+    return ByteString.wrap(buffer, offset, length);
+  }
+
+  /**
+   * An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
+   *
+   * @param buffer the Java NIO buffer to be wrapped
+   * @return a {@link ByteString} backed by the provided buffer
    */
   public static ByteString unsafeWrap(ByteBuffer buffer) {
-    if (buffer.hasArray()) {
-      final int offset = buffer.arrayOffset();
-      return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
-    } else {
-      return new NioByteString(buffer);
-    }
+    return ByteString.wrap(buffer);
   }
+
+  /**
+   * Writes the given {@link ByteString} to the provided {@link ByteOutput}. Calling this method may
+   * result in multiple operations on the target {@link ByteOutput}
+   * (i.e. for roped {@link ByteString}s).
+   *
+   * <p>This method exposes the internal backing buffer(s) of the {@link ByteString} to the {@link
+   * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+   * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+   *
+   * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+   * so may result in corrupted data, which would be difficult to debug.
+   *
+   * @param bytes the {@link ByteString} to be written
+   * @param  output  the output to receive the bytes
+   * @throws IOException  if an I/O error occurs
+   */
+  public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException {
+    bytes.writeTo(output);
+  }
+
 }
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
new file mode 100644
index 0000000..c9e2904
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -0,0 +1,601 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/** Utility class for working with unsafe operations. */
+final class UnsafeUtil {
+  private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
+  private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+  private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
+  private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
+      supportsUnsafeByteBufferOperations();
+  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+
+  private static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(byte[].class);
+  // Micro-optimization: we can assume a scale of 1 and skip the multiply
+  // private static final long BYTE_ARRAY_INDEX_SCALE = 1;
+
+  private static final long BOOLEAN_ARRAY_BASE_OFFSET = arrayBaseOffset(boolean[].class);
+  private static final long BOOLEAN_ARRAY_INDEX_SCALE = arrayIndexScale(boolean[].class);
+
+  private static final long INT_ARRAY_BASE_OFFSET = arrayBaseOffset(int[].class);
+  private static final long INT_ARRAY_INDEX_SCALE = arrayIndexScale(int[].class);
+
+  private static final long LONG_ARRAY_BASE_OFFSET = arrayBaseOffset(long[].class);
+  private static final long LONG_ARRAY_INDEX_SCALE = arrayIndexScale(long[].class);
+
+  private static final long FLOAT_ARRAY_BASE_OFFSET = arrayBaseOffset(float[].class);
+  private static final long FLOAT_ARRAY_INDEX_SCALE = arrayIndexScale(float[].class);
+
+  private static final long DOUBLE_ARRAY_BASE_OFFSET = arrayBaseOffset(double[].class);
+  private static final long DOUBLE_ARRAY_INDEX_SCALE = arrayIndexScale(double[].class);
+
+  private static final long OBJECT_ARRAY_BASE_OFFSET = arrayBaseOffset(Object[].class);
+  private static final long OBJECT_ARRAY_INDEX_SCALE = arrayIndexScale(Object[].class);
+
+  private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
+
+  private static final long STRING_VALUE_OFFSET = fieldOffset(stringValueField());
+
+  private UnsafeUtil() {}
+
+  static boolean hasUnsafeArrayOperations() {
+    return HAS_UNSAFE_ARRAY_OPERATIONS;
+  }
+
+  static boolean hasUnsafeByteBufferOperations() {
+    return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
+  }
+
+
+  static long objectFieldOffset(Field field) {
+    return MEMORY_ACCESSOR.objectFieldOffset(field);
+  }
+
+  private static int arrayBaseOffset(Class<?> clazz) {
+    return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(clazz) : -1;
+  }
+
+  private static int arrayIndexScale(Class<?> clazz) {
+    return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayIndexScale(clazz) : -1;
+  }
+
+  static byte getByte(Object target, long offset) {
+    return MEMORY_ACCESSOR.getByte(target, offset);
+  }
+
+  static void putByte(Object target, long offset, byte value) {
+    MEMORY_ACCESSOR.putByte(target, offset, value);
+  }
+
+  static int getInt(Object target, long offset) {
+    return MEMORY_ACCESSOR.getInt(target, offset);
+  }
+
+  static void putInt(Object target, long offset, int value) {
+    MEMORY_ACCESSOR.putInt(target, offset, value);
+  }
+
+  static long getLong(Object target, long offset) {
+    return MEMORY_ACCESSOR.getLong(target, offset);
+  }
+
+  static void putLong(Object target, long offset, long value) {
+    MEMORY_ACCESSOR.putLong(target, offset, value);
+  }
+
+  static boolean getBoolean(Object target, long offset) {
+    return MEMORY_ACCESSOR.getBoolean(target, offset);
+  }
+
+  static void putBoolean(Object target, long offset, boolean value) {
+    MEMORY_ACCESSOR.putBoolean(target, offset, value);
+  }
+
+  static float getFloat(Object target, long offset) {
+    return MEMORY_ACCESSOR.getFloat(target, offset);
+  }
+
+  static void putFloat(Object target, long offset, float value) {
+    MEMORY_ACCESSOR.putFloat(target, offset, value);
+  }
+
+  static double getDouble(Object target, long offset) {
+    return MEMORY_ACCESSOR.getDouble(target, offset);
+  }
+
+  static void putDouble(Object target, long offset, double value) {
+    MEMORY_ACCESSOR.putDouble(target, offset, value);
+  }
+
+  static Object getObject(Object target, long offset) {
+    return MEMORY_ACCESSOR.getObject(target, offset);
+  }
+
+  static void putObject(Object target, long offset, Object value) {
+    MEMORY_ACCESSOR.putObject(target, offset, value);
+  }
+
+  static byte getByte(byte[] target, long index) {
+    return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
+  }
+
+  static void putByte(byte[] target, long index, byte value) {
+    MEMORY_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value);
+  }
+
+  static int getInt(int[] target, long index) {
+    return MEMORY_ACCESSOR.getInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE));
+  }
+
+  static void putInt(int[] target, long index, int value) {
+    MEMORY_ACCESSOR.putInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE), value);
+  }
+
+  static long getLong(long[] target, long index) {
+    return MEMORY_ACCESSOR.getLong(
+        target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE));
+  }
+
+  static void putLong(long[] target, long index, long value) {
+    MEMORY_ACCESSOR.putLong(
+        target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE), value);
+  }
+
+  static boolean getBoolean(boolean[] target, long index) {
+    return MEMORY_ACCESSOR.getBoolean(
+        target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE));
+  }
+
+  static void putBoolean(boolean[] target, long index, boolean value) {
+    MEMORY_ACCESSOR.putBoolean(
+        target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE), value);
+  }
+
+  static float getFloat(float[] target, long index) {
+    return MEMORY_ACCESSOR.getFloat(
+        target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE));
+  }
+
+  static void putFloat(float[] target, long index, float value) {
+    MEMORY_ACCESSOR.putFloat(
+        target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE), value);
+  }
+
+  static double getDouble(double[] target, long index) {
+    return MEMORY_ACCESSOR.getDouble(
+        target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE));
+  }
+
+  static void putDouble(double[] target, long index, double value) {
+    MEMORY_ACCESSOR.putDouble(
+        target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE), value);
+  }
+
+  static Object getObject(Object[] target, long index) {
+    return MEMORY_ACCESSOR.getObject(
+        target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE));
+  }
+
+  static void putObject(Object[] target, long index, Object value) {
+    MEMORY_ACCESSOR.putObject(
+        target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE), value);
+  }
+
+  static void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+    MEMORY_ACCESSOR.copyMemory(src, srcIndex, targetOffset, length);
+  }
+
+  static void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+    MEMORY_ACCESSOR.copyMemory(srcOffset, target, targetIndex, length);
+  }
+
+  static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length) {
+    System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length); 
+  }
+
+  static byte getByte(long address) {
+    return MEMORY_ACCESSOR.getByte(address);
+  }
+
+  static void putByte(long address, byte value) {
+    MEMORY_ACCESSOR.putByte(address, value);
+  }
+
+  static int getInt(long address) {
+    return MEMORY_ACCESSOR.getInt(address);
+  }
+
+  static void putInt(long address, int value) {
+    MEMORY_ACCESSOR.putInt(address, value);
+  }
+
+  static long getLong(long address) {
+    return MEMORY_ACCESSOR.getLong(address);
+  }
+
+  static void putLong(long address, long value) {
+    MEMORY_ACCESSOR.putLong(address, value);
+  }
+
+  /**
+   * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
+   */
+  static long addressOffset(ByteBuffer buffer) {
+    return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+  }
+
+  /**
+   * Returns a new {@link String} backed by the given {@code chars}. The char array should not
+   * be mutated any more after calling this function.
+   */
+  static String moveToString(char[] chars) {
+    if (STRING_VALUE_OFFSET == -1) {
+      // In the off-chance that this JDK does not implement String as we'd expect, just do a copy.
+      return new String(chars);
+    }
+    final String str;
+    try {
+      str = (String) UNSAFE.allocateInstance(String.class);
+    } catch (InstantiationException e) {
+      // This should never happen, but return a copy as a fallback just in case.
+      return new String(chars);
+    }
+    putObject(str, STRING_VALUE_OFFSET, chars);
+    return str;
+  }
+
+  static Object getStaticObject(Field field) {
+    return MEMORY_ACCESSOR.getStaticObject(field);
+  }
+
+  /**
+   * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
+   */
+  static sun.misc.Unsafe getUnsafe() {
+    sun.misc.Unsafe unsafe = null;
+    try {
+      unsafe =
+          AccessController.doPrivileged(
+              new PrivilegedExceptionAction<sun.misc.Unsafe>() {
+                @Override
+                public sun.misc.Unsafe run() throws Exception {
+                  Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+                  for (Field f : k.getDeclaredFields()) {
+                    f.setAccessible(true);
+                    Object x = f.get(null);
+                    if (k.isInstance(x)) {
+                      return k.cast(x);
+                    }
+                  }
+                  // The sun.misc.Unsafe field does not exist.
+                  return null;
+                }
+              });
+    } catch (Throwable e) {
+      // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+      // for Unsafe.
+    }
+    return unsafe;
+  }
+
+  /** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
+  private static MemoryAccessor getMemoryAccessor() {
+    if (UNSAFE == null) {
+      return null;
+    }
+    return new JvmMemoryAccessor(UNSAFE);
+  }
+
+  /** Indicates whether or not unsafe array operations are supported on this platform. */
+  private static boolean supportsUnsafeArrayOperations() {
+    if (UNSAFE == null) {
+      return false;
+    }
+    try {
+      Class<?> clazz = UNSAFE.getClass();
+      clazz.getMethod("objectFieldOffset", Field.class);
+      clazz.getMethod("arrayBaseOffset", Class.class);
+      clazz.getMethod("arrayIndexScale", Class.class);
+      clazz.getMethod("getInt", Object.class, long.class);
+      clazz.getMethod("putInt", Object.class, long.class, int.class);
+      clazz.getMethod("getLong", Object.class, long.class);
+      clazz.getMethod("putLong", Object.class, long.class, long.class);
+      clazz.getMethod("getObject", Object.class, long.class);
+      clazz.getMethod("putObject", Object.class, long.class, Object.class);
+      clazz.getMethod("getByte", Object.class, long.class);
+      clazz.getMethod("putByte", Object.class, long.class, byte.class);
+      clazz.getMethod("getBoolean", Object.class, long.class);
+      clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
+      clazz.getMethod("getFloat", Object.class, long.class);
+      clazz.getMethod("putFloat", Object.class, long.class, float.class);
+      clazz.getMethod("getDouble", Object.class, long.class);
+      clazz.getMethod("putDouble", Object.class, long.class, double.class);
+
+      return true;
+    } catch (Throwable e) {
+      logger.log(
+          Level.WARNING,
+          "platform method missing - proto runtime falling back to safer methods: " + e);
+    }
+    return false;
+  }
+
+  private static boolean supportsUnsafeByteBufferOperations() {
+    if (UNSAFE == null) {
+      return false;
+    }
+    try {
+      Class<?> clazz = UNSAFE.getClass();
+      // Methods for getting direct buffer address.
+      clazz.getMethod("objectFieldOffset", Field.class);
+      clazz.getMethod("getLong", Object.class, long.class);
+
+      if (bufferAddressField() == null) {
+        return false;
+      }
+
+      clazz.getMethod("getByte", long.class);
+      clazz.getMethod("putByte", long.class, byte.class);
+      clazz.getMethod("getInt", long.class);
+      clazz.getMethod("putInt", long.class, int.class);
+      clazz.getMethod("getLong", long.class);
+      clazz.getMethod("putLong", long.class, long.class);
+      clazz.getMethod("copyMemory", long.class, long.class, long.class);
+      clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+      return true;
+    } catch (Throwable e) {
+      logger.log(
+          Level.WARNING,
+          "platform method missing - proto runtime falling back to safer methods: " + e);
+    }
+    return false;
+  }
+
+
+  /** Finds the address field within a direct {@link Buffer}. */
+  private static Field bufferAddressField() {
+    Field field = field(Buffer.class, "address");
+    return field != null && field.getType() == long.class ? field : null;
+  }
+
+  /** Finds the value field within a {@link String}. */
+  private static Field stringValueField() {
+    Field field = field(String.class, "value");
+    return field != null && field.getType() == char[].class ? field : null;
+  }
+
+  /**
+   * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
+   * available.
+   */
+  private static long fieldOffset(Field field) {
+    return field == null || MEMORY_ACCESSOR == null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(field);
+  }
+
+  /**
+   * Gets the field with the given name within the class, or {@code null} if not found. If found,
+   * the field is made accessible.
+   */
+  private static Field field(Class<?> clazz, String fieldName) {
+    Field field;
+    try {
+      field = clazz.getDeclaredField(fieldName);
+      field.setAccessible(true);
+    } catch (Throwable t) {
+      // Failed to access the fields.
+      field = null;
+    }
+    return field;
+  }
+
+  private abstract static class MemoryAccessor {
+
+    sun.misc.Unsafe unsafe;
+
+    MemoryAccessor(sun.misc.Unsafe unsafe) {
+      this.unsafe = unsafe;
+    }
+
+    public final long objectFieldOffset(Field field) {
+      return unsafe.objectFieldOffset(field);
+    }
+
+    public abstract byte getByte(Object target, long offset);
+
+    public abstract void putByte(Object target, long offset, byte value);
+
+    public final int getInt(Object target, long offset) {
+      return unsafe.getInt(target, offset);
+    }
+
+    public final void putInt(Object target, long offset, int value) {
+      unsafe.putInt(target, offset, value);
+    }
+
+    public final long getLong(Object target, long offset) {
+      return unsafe.getLong(target, offset);
+    }
+
+    public final void putLong(Object target, long offset, long value) {
+      unsafe.putLong(target, offset, value);
+    }
+
+    public abstract boolean getBoolean(Object target, long offset);
+
+    public abstract void putBoolean(Object target, long offset, boolean value);
+
+    public abstract float getFloat(Object target, long offset);
+
+    public abstract void putFloat(Object target, long offset, float value);
+
+    public abstract double getDouble(Object target, long offset);
+
+    public abstract void putDouble(Object target, long offset, double value);
+
+    public final Object getObject(Object target, long offset) {
+      return unsafe.getObject(target, offset);
+    }
+
+    public final void putObject(Object target, long offset, Object value) {
+      unsafe.putObject(target, offset, value);
+    }
+
+    public final int arrayBaseOffset(Class<?> clazz) {
+      return unsafe.arrayBaseOffset(clazz);
+    }
+
+    public final int arrayIndexScale(Class<?> clazz) {
+      return unsafe.arrayIndexScale(clazz);
+    }
+
+    public abstract byte getByte(long address);
+
+    public abstract void putByte(long address, byte value);
+
+    public abstract int getInt(long address);
+
+    public abstract void putInt(long address, int value);
+
+    public abstract long getLong(long address);
+
+    public abstract void putLong(long address, long value);
+
+    public abstract Object getStaticObject(Field field);
+    
+    public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
+    
+    public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
+  }
+
+  private static final class JvmMemoryAccessor extends MemoryAccessor {
+
+    JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
+      super(unsafe);
+    }
+
+    @Override
+    public byte getByte(long address) {
+      return unsafe.getByte(address);
+    }
+
+    @Override
+    public void putByte(long address, byte value) {
+      unsafe.putByte(address, value);
+    }
+
+    @Override
+    public int getInt(long address) {
+      return unsafe.getInt(address);
+    }
+
+    @Override
+    public void putInt(long address, int value) {
+      unsafe.putInt(address, value);
+    }
+
+    @Override
+    public long getLong(long address) {
+      return unsafe.getLong(address);
+    }
+
+    @Override
+    public void putLong(long address, long value) {
+      unsafe.putLong(address, value);
+    }
+
+    @Override
+    public byte getByte(Object target, long offset) {
+      return unsafe.getByte(target, offset);
+    }
+
+    @Override
+    public void putByte(Object target, long offset, byte value) {
+      unsafe.putByte(target, offset, value);
+    }
+
+    @Override
+    public boolean getBoolean(Object target, long offset) {
+      return unsafe.getBoolean(target, offset);
+    }
+
+    @Override
+    public void putBoolean(Object target, long offset, boolean value) {
+      unsafe.putBoolean(target, offset, value);
+    }
+
+    @Override
+    public float getFloat(Object target, long offset) {
+      return unsafe.getFloat(target, offset);
+    }
+
+    @Override
+    public void putFloat(Object target, long offset, float value) {
+      unsafe.putFloat(target, offset, value);
+    }
+
+    @Override
+    public double getDouble(Object target, long offset) {
+      return unsafe.getDouble(target, offset);
+    }
+
+    @Override
+    public void putDouble(Object target, long offset, double value) {
+      unsafe.putDouble(target, offset, value);
+    }
+    
+    @Override 
+    public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+      unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
+    }
+    
+    @Override
+    public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+      unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
+    }
+
+    @Override
+    public Object getStaticObject(Field field) {
+      return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
+    }
+  }
+
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 48c7e9e..6968abb 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -30,6 +30,20 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.UnsafeUtil.addressOffset;
+import static com.google.protobuf.UnsafeUtil.hasUnsafeArrayOperations;
+import static com.google.protobuf.UnsafeUtil.hasUnsafeByteBufferOperations;
+import static java.lang.Character.MAX_SURROGATE;
+import static java.lang.Character.MIN_HIGH_SURROGATE;
+import static java.lang.Character.MIN_LOW_SURROGATE;
+import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
+import static java.lang.Character.MIN_SURROGATE;
+import static java.lang.Character.isSurrogatePair;
+import static java.lang.Character.toCodePoint;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
 /**
  * A set of low-level, high-performance static utility methods related
  * to the UTF-8 character encoding.  This class has no dependencies
@@ -64,9 +78,23 @@
  *
  * @author martinrb@google.com (Martin Buchholz)
  */
+// TODO(nathanmittler): Copy changes in this class back to Guava
 final class Utf8 {
-  private Utf8() {}
-  
+
+  /**
+   * UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations
+   * depending on what is available on the platform. The processor is the platform-optimized
+   * delegate for which all methods are delegated directly to.
+   */
+  private static final Processor processor =
+      UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor();
+
+  /**
+   * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII
+   * characters (i.e. any byte >= 0x80).
+   */
+  private static final long ASCII_MASK_LONG = 0x8080808080808080L;
+
   /**
    * Maximum number of bytes per Java UTF-16 char in UTF-8.
    * @see java.nio.charset.CharsetEncoder#maxBytesPerChar()
@@ -85,6 +113,18 @@
    */
   public static final int MALFORMED = -1;
 
+  /**
+   * Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length
+   * above which to employ an optimized algorithm for counting ASCII characters. The reason for this
+   * threshold is that for small strings, the optimization may not be beneficial or may even
+   * negatively impact performance since it requires additional logic to avoid unaligned reads
+   * (when calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial
+   * offset is unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()}
+   * which provides a performance improvement that entirely subsumes the cost of the additional
+   * logic.
+   */
+  private static final int UNSAFE_COUNT_ASCII_THRESHOLD = 16;
+
   // Other state values include the partial bytes of the incomplete
   // character to be decoded in the simplest way: we pack the bytes
   // into the state int in little-endian order.  For example:
@@ -112,7 +152,7 @@
    * isValidUtf8(bytes, 0, bytes.length)}.
    */
   public static boolean isValidUtf8(byte[] bytes) {
-    return isValidUtf8(bytes, 0, bytes.length);
+    return processor.isValidUtf8(bytes, 0, bytes.length);
   }
 
   /**
@@ -125,7 +165,7 @@
    * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
    */
   public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
-    return partialIsValidUtf8(bytes, index, limit) == COMPLETE;
+    return processor.isValidUtf8(bytes, index, limit);
   }
 
   /**
@@ -146,183 +186,8 @@
    * decode the character when passed to a subsequent invocation of a
    * partial decoding method.
    */
-  public static int partialIsValidUtf8(
-      int state, byte[] bytes, int index, int limit) {
-    if (state != COMPLETE) {
-      // The previous decoding operation was incomplete (or malformed).
-      // We look for a well-formed sequence consisting of bytes from
-      // the previous decoding operation (stored in state) together
-      // with bytes from the array slice.
-      //
-      // We expect such "straddler characters" to be rare.
-
-      if (index >= limit) {  // No bytes? No progress.
-        return state;
-      }
-      int byte1 = (byte) state;
-      // byte1 is never ASCII.
-      if (byte1 < (byte) 0xE0) {
-        // two-byte form
-
-        // Simultaneously checks for illegal trailing-byte in
-        // leading position and overlong 2-byte form.
-        if (byte1 < (byte) 0xC2 ||
-            // byte2 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else if (byte1 < (byte) 0xF0) {
-        // three-byte form
-
-        // Get byte2 from saved state or array
-        int byte2 = (byte) ~(state >> 8);
-        if (byte2 == 0) {
-          byte2 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2);
-          }
-        }
-        if (byte2 > (byte) 0xBF ||
-            // overlong? 5 most significant bits must not all be zero
-            (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
-            // illegal surrogate codepoint?
-            (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else {
-        // four-byte form
-
-        // Get byte2 and byte3 from saved state or array
-        int byte2 = (byte) ~(state >> 8);
-        int byte3 = 0;
-        if (byte2 == 0) {
-          byte2 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2);
-          }
-        } else {
-          byte3 = (byte) (state >> 16);
-        }
-        if (byte3 == 0) {
-          byte3 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2, byte3);
-          }
-        }
-
-        // If we were called with state == MALFORMED, then byte1 is 0xFF,
-        // which never occurs in well-formed UTF-8, and so we will return
-        // MALFORMED again below.
-
-        if (byte2 > (byte) 0xBF ||
-            // Check that 1 <= plane <= 16.  Tricky optimized form of:
-            // if (byte1 > (byte) 0xF4 ||
-            //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
-            //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
-            (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
-            // byte3 trailing-byte test
-            byte3 > (byte) 0xBF ||
-            // byte4 trailing-byte test
-             bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      }
-    }
-
-    return partialIsValidUtf8(bytes, index, limit);
-  }
-
-  /**
-   * Tells whether the given byte array slice is a well-formed,
-   * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
-   * to be checked extends from index {@code index}, inclusive, to
-   * {@code limit}, exclusive.
-   *
-   * <p>This is a convenience method, equivalent to a call to {@code
-   * partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}.
-   *
-   * @return {@link #MALFORMED} if the partial byte sequence is
-   * definitely not well-formed, {@link #COMPLETE} if it is well-formed
-   * (no additional input needed), or if the byte sequence is
-   * "incomplete", i.e. apparently terminated in the middle of a character,
-   * an opaque integer "state" value containing enough information to
-   * decode the character when passed to a subsequent invocation of a
-   * partial decoding method.
-   */
-  public static int partialIsValidUtf8(
-      byte[] bytes, int index, int limit) {
-    // Optimize for 100% ASCII.
-    // Hotspot loves small simple top-level loops like this.
-    while (index < limit && bytes[index] >= 0) {
-      index++;
-    }
-
-    return (index >= limit) ? COMPLETE :
-        partialIsValidUtf8NonAscii(bytes, index, limit);
-  }
-
-  private static int partialIsValidUtf8NonAscii(
-      byte[] bytes, int index, int limit) {
-    for (;;) {
-      int byte1, byte2;
-
-      // Optimize for interior runs of ASCII bytes.
-      do {
-        if (index >= limit) {
-          return COMPLETE;
-        }
-      } while ((byte1 = bytes[index++]) >= 0);
-
-      if (byte1 < (byte) 0xE0) {
-        // two-byte form
-
-        if (index >= limit) {
-          return byte1;
-        }
-
-        // Simultaneously checks for illegal trailing-byte in
-        // leading position and overlong 2-byte form.
-        if (byte1 < (byte) 0xC2 ||
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else if (byte1 < (byte) 0xF0) {
-        // three-byte form
-
-        if (index >= limit - 1) { // incomplete sequence
-          return incompleteStateFor(bytes, index, limit);
-        }
-        if ((byte2 = bytes[index++]) > (byte) 0xBF ||
-            // overlong? 5 most significant bits must not all be zero
-            (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
-            // check for illegal surrogate codepoints
-            (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else {
-        // four-byte form
-
-        if (index >= limit - 2) {  // incomplete sequence
-          return incompleteStateFor(bytes, index, limit);
-        }
-        if ((byte2 = bytes[index++]) > (byte) 0xBF ||
-            // Check that 1 <= plane <= 16.  Tricky optimized form of:
-            // if (byte1 > (byte) 0xF4 ||
-            //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
-            //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
-            (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF ||
-            // byte4 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      }
-    }
+  public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+    return processor.partialIsValidUtf8(state, bytes, index, limit);
   }
 
   private static int incompleteStateFor(int byte1) {
@@ -352,19 +217,31 @@
       default: throw new AssertionError();
     }
   }
-  
+
+  private static int incompleteStateFor(
+      final ByteBuffer buffer, final int byte1, final int index, final int remaining) {
+    switch (remaining) {
+      case 0:
+        return incompleteStateFor(byte1);
+      case 1:
+        return incompleteStateFor(byte1, buffer.get(index));
+      case 2:
+        return incompleteStateFor(byte1, buffer.get(index), buffer.get(index + 1));
+      default:
+        throw new AssertionError();
+    }
+  }
 
   // These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw
   // a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
   // fallback to more lenient behavior.
   
   static class UnpairedSurrogateException extends IllegalArgumentException {
-    
-    private UnpairedSurrogateException(int index, int length) {
+    UnpairedSurrogateException(int index, int length) {
       super("Unpaired surrogate at index " + index + " of " + length);
     }
   }
-  
+
   /**
    * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
    * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
@@ -416,7 +293,7 @@
         if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
           // Check that we have a well-formed surrogate pair.
           int cp = Character.codePointAt(sequence, i);
-          if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+          if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
             throw new UnpairedSurrogateException(i, utf16Length);
           }
           i++;
@@ -426,56 +303,1738 @@
     return utf8Length;
   }
 
-  static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
-    int utf16Length = sequence.length();
-    int j = offset;
-    int i = 0;
-    int limit = offset + length;
-    // Designed to take advantage of
-    // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
-    for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
-      bytes[j + i] = (byte) c;
-    }
-    if (i == utf16Length) {
-      return j + utf16Length;
-    }
-    j += i;
-    for (char c; i < utf16Length; i++) {
-      c = sequence.charAt(i);
-      if (c < 0x80 && j < limit) {
-        bytes[j++] = (byte) c;
-      } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
-        bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
-        bytes[j++] = (byte) (0x80 | (0x3F & c));
-      } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
-        // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
-        bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
-        bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
-        bytes[j++] = (byte) (0x80 | (0x3F & c));
-      } else if (j <= limit - 4) {
-        // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
-        final char low;
-        if (i + 1 == sequence.length()
-                || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
-          throw new UnpairedSurrogateException((i - 1), utf16Length);
-        }
-        int codePoint = Character.toCodePoint(c, low);
-        bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
-        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
-        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
-        bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
-      } else {
-        // If we are surrogates and we're not a surrogate pair, always throw an
-        // IllegalArgumentException instead of an ArrayOutOfBoundsException.
-        if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
-            && (i + 1 == sequence.length()
-                || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
-          throw new UnpairedSurrogateException(i, utf16Length);
-        }
-        throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
-      }
-    }
-    return j;
+  static int encode(CharSequence in, byte[] out, int offset, int length) {
+    return processor.encodeUtf8(in, out, offset, length);
   }
   // End Guava UTF-8 methods.
+
+  /**
+   * Determines if the given {@link ByteBuffer} is a valid UTF-8 string.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param buffer the buffer to check.
+   * @see Utf8#isValidUtf8(byte[], int, int)
+   */
+  static boolean isValidUtf8(ByteBuffer buffer) {
+    return processor.isValidUtf8(buffer, buffer.position(), buffer.remaining());
+  }
+
+  /**
+   * Determines if the given {@link ByteBuffer} is a partially valid UTF-8 string.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param buffer the buffer to check.
+   * @see Utf8#partialIsValidUtf8(int, byte[], int, int)
+   */
+  static int partialIsValidUtf8(int state, ByteBuffer buffer, int index, int limit) {
+    return processor.partialIsValidUtf8(state, buffer, index, limit);
+  }
+
+  /**
+   * Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
+   *
+   * @throws InvalidProtocolBufferException if the input is not valid UTF-8.
+   */
+  static String decodeUtf8(ByteBuffer buffer, int index, int size)
+      throws InvalidProtocolBufferException {
+    return processor.decodeUtf8(buffer, index, size);
+  }
+
+  /**
+   * Decodes the given UTF-8 encoded byte array slice into a {@link String}.
+   *
+   * @throws InvalidProtocolBufferException if the input is not valid UTF-8.
+   */
+  static String decodeUtf8(byte[] bytes, int index, int size)
+      throws InvalidProtocolBufferException {
+    return processor.decodeUtf8(bytes, index, size);
+  }
+
+  /**
+   * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param in the source string to be encoded
+   * @param out the target buffer to receive the encoded string.
+   * @see Utf8#encode(CharSequence, byte[], int, int)
+   */
+  static void encodeUtf8(CharSequence in, ByteBuffer out) {
+    processor.encodeUtf8(in, out);
+  }
+
+  /**
+   * Counts (approximately) the number of consecutive ASCII characters in the given buffer.
+   * The byte order of the {@link ByteBuffer} does not matter, so performance can be improved if
+   * native byte order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}).
+   *
+   * @param buffer the buffer to be scanned for ASCII chars
+   * @param index the starting index of the scan
+   * @param limit the limit within buffer for the scan
+   * @return the number of ASCII characters found. The stopping position will be at or
+   * before the first non-ASCII byte.
+   */
+  private static int estimateConsecutiveAscii(ByteBuffer buffer, int index, int limit) {
+    int i = index;
+    final int lim = limit - 7;
+    // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+    // To speed things up further, we're reading longs instead of bytes so we use a mask to
+    // determine if any byte in the current long is non-ASCII.
+    for (; i < lim && (buffer.getLong(i) & ASCII_MASK_LONG) == 0; i += 8) {}
+    return i - index;
+  }
+
+  /**
+   * A processor of UTF-8 strings, providing methods for checking validity and encoding.
+   */
+  // TODO(nathanmittler): Add support for Memory/MemoryBlock on Android.
+  abstract static class Processor {
+    /**
+     * Returns {@code true} if the given byte array slice is a
+     * well-formed UTF-8 byte sequence.  The range of bytes to be
+     * checked extends from index {@code index}, inclusive, to {@code
+     * limit}, exclusive.
+     *
+     * <p>This is a convenience method, equivalent to {@code
+     * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+     */
+    final boolean isValidUtf8(byte[] bytes, int index, int limit) {
+      return partialIsValidUtf8(COMPLETE, bytes, index, limit) == COMPLETE;
+    }
+
+    /**
+     * Tells whether the given byte array slice is a well-formed,
+     * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
+     * to be checked extends from index {@code index}, inclusive, to
+     * {@code limit}, exclusive.
+     *
+     * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
+     * operation) or the value returned from a call to a partial decoding method
+     * for the previous bytes
+     *
+     * @return {@link #MALFORMED} if the partial byte sequence is
+     * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+     * (no additional input needed), or if the byte sequence is
+     * "incomplete", i.e. apparently terminated in the middle of a character,
+     * an opaque integer "state" value containing enough information to
+     * decode the character when passed to a subsequent invocation of a
+     * partial decoding method.
+     */
+    abstract int partialIsValidUtf8(int state, byte[] bytes, int index, int limit);
+
+    /**
+     * Returns {@code true} if the given portion of the {@link ByteBuffer} is a
+     * well-formed UTF-8 byte sequence.  The range of bytes to be
+     * checked extends from index {@code index}, inclusive, to {@code
+     * limit}, exclusive.
+     *
+     * <p>This is a convenience method, equivalent to {@code
+     * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+     */
+    final boolean isValidUtf8(ByteBuffer buffer, int index, int limit) {
+      return partialIsValidUtf8(COMPLETE, buffer, index, limit) == COMPLETE;
+    }
+
+    /**
+     * Indicates whether or not the given buffer contains a valid UTF-8 string.
+     *
+     * @param buffer the buffer to check.
+     * @return {@code true} if the given buffer contains a valid UTF-8 string.
+     */
+    final int partialIsValidUtf8(
+        final int state, final ByteBuffer buffer, int index, final int limit) {
+      if (buffer.hasArray()) {
+        final int offset = buffer.arrayOffset();
+        return partialIsValidUtf8(state, buffer.array(), offset + index, offset + limit);
+      } else if (buffer.isDirect()){
+        return partialIsValidUtf8Direct(state, buffer, index, limit);
+      }
+      return partialIsValidUtf8Default(state, buffer, index, limit);
+    }
+
+    /**
+     * Performs validation for direct {@link ByteBuffer} instances.
+     */
+    abstract int partialIsValidUtf8Direct(
+        final int state, final ByteBuffer buffer, int index, final int limit);
+
+    /**
+     * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+     * than potentially faster approaches. This first completes validation for the current
+     * character (provided by {@code state}) and then finishes validation for the sequence.
+     */
+    final int partialIsValidUtf8Default(
+        final int state, final ByteBuffer buffer, int index, final int limit) {
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (index >= limit) { // No bytes? No progress.
+          return state;
+        }
+
+        byte byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          byte byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          byte byte2 = (byte) ~(state >> 8);
+          byte byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      // Finish validation for the sequence.
+      return partialIsValidUtf8(buffer, index, limit);
+    }
+
+    /**
+     * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+     * than potentially faster approaches.
+     */
+    private static int partialIsValidUtf8(final ByteBuffer buffer, int index, final int limit) {
+      index += estimateConsecutiveAscii(buffer, index, limit);
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1;
+        do {
+          if (index >= limit) {
+            return COMPLETE;
+          }
+        } while ((byte1 = buffer.get(index++)) >= 0);
+
+        // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form (110xxxxx 10xxxxxx)
+          if (index >= limit) {
+            // Incomplete sequence
+            return byte1;
+          }
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2 || buffer.get(index) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+          index++;
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+          if (index >= limit - 1) {
+            // Incomplete sequence
+            return incompleteStateFor(buffer, byte1, index, limit - index);
+          }
+
+          final byte byte2 = buffer.get(index++);
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || buffer.get(index) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+          index++;
+        } else {
+          // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+          if (index >= limit - 2) {
+            // Incomplete sequence
+            return incompleteStateFor(buffer, byte1, index, limit - index);
+          }
+
+          // TODO(nathanmittler): Consider using getInt() to improve performance.
+          final int byte2 = buffer.get(index++);
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    /**
+     * Decodes the given byte array slice into a {@link String}.
+     *
+     * @throws InvalidProtocolBufferException if the byte array slice is not valid UTF-8.
+     */
+    abstract String decodeUtf8(byte[] bytes, int index, int size)
+        throws InvalidProtocolBufferException;
+
+    /**
+     * Decodes the given portion of the {@link ByteBuffer} into a {@link String}.
+     *
+     * @throws InvalidProtocolBufferException if the portion of the buffer is not valid UTF-8.
+     */
+    final String decodeUtf8(ByteBuffer buffer, int index, int size)
+        throws InvalidProtocolBufferException {
+      if (buffer.hasArray()) {
+        final int offset = buffer.arrayOffset();
+        return decodeUtf8(buffer.array(), offset + index, size);
+      } else if (buffer.isDirect()) {
+        return decodeUtf8Direct(buffer, index, size);
+      }
+      return decodeUtf8Default(buffer, index, size);
+    }
+
+    /**
+     * Decodes direct {@link ByteBuffer} instances into {@link String}.
+     */
+    abstract String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+        throws InvalidProtocolBufferException;
+
+    /**
+     * Decodes {@link ByteBuffer} instances using the {@link ByteBuffer} API rather than
+     * potentially faster approaches.
+     */
+    final String decodeUtf8Default(ByteBuffer buffer, int index, int size)
+        throws InvalidProtocolBufferException {
+      // Bitwise OR combines the sign bits so any negative value fails the check.
+      if ((index | size | buffer.limit() - index - size) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, size));
+      }
+
+      int offset = index;
+      final int limit = offset + size;
+
+      // The longest possible resulting String is the same as the number of input bytes, when it is
+      // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+      char[] resultArr = new char[size];
+      int resultPos = 0;
+
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (offset < limit) {
+        byte b = buffer.get(offset);
+        if (!DecodeUtil.isOneByte(b)) {
+          break;
+        }
+        offset++;
+        DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+      }
+
+      while (offset < limit) {
+        byte byte1 = buffer.get(offset++);
+        if (DecodeUtil.isOneByte(byte1)) {
+          DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+          // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+          // extra optimized loop to take care of these runs.
+          while (offset < limit) {
+            byte b = buffer.get(offset);
+            if (!DecodeUtil.isOneByte(b)) {
+              break;
+            }
+            offset++;
+            DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+          }
+        } else if (DecodeUtil.isTwoBytes(byte1)) {
+          if (offset >= limit) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleTwoBytes(
+              byte1, /* byte2 */ buffer.get(offset++), resultArr, resultPos++);
+        } else if (DecodeUtil.isThreeBytes(byte1)) {
+          if (offset >= limit - 1) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleThreeBytes(
+              byte1,
+              /* byte2 */ buffer.get(offset++),
+              /* byte3 */ buffer.get(offset++),
+              resultArr,
+              resultPos++);
+        } else {
+          if (offset >= limit - 2) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleFourBytes(
+              byte1,
+              /* byte2 */ buffer.get(offset++),
+              /* byte3 */ buffer.get(offset++),
+              /* byte4 */ buffer.get(offset++),
+              resultArr,
+              resultPos++);
+          // 4-byte case requires two chars.
+          resultPos++;
+        }
+      }
+
+      return new String(resultArr, 0, resultPos);
+    }
+
+    /**
+     * Encodes an input character sequence ({@code in}) to UTF-8 in the target array ({@code out}).
+     * For a string, this method is similar to
+     * <pre>{@code
+     * byte[] a = string.getBytes(UTF_8);
+     * System.arraycopy(a, 0, bytes, offset, a.length);
+     * return offset + a.length;
+     * }</pre>
+     *
+     * but is more efficient in both time and space. One key difference is that this method
+     * requires paired surrogates, and therefore does not support chunking.
+     * While {@code String.getBytes(UTF_8)} replaces unpaired surrogates with the default
+     * replacement character, this method throws {@link UnpairedSurrogateException}.
+     *
+     * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+     * compute the exact amount needed, or leave room for 
+     * {@code Utf8.MAX_BYTES_PER_CHAR * sequence.length()}, which is the largest possible number
+     * of bytes that any input can be encoded to.
+     *
+     * @param in the input character sequence to be encoded
+     * @param out the target array
+     * @param offset the starting offset in {@code bytes} to start writing at
+     * @param length the length of the {@code bytes}, starting from {@code offset}
+     * @throws UnpairedSurrogateException if {@code sequence} contains ill-formed UTF-16 (unpaired
+     *     surrogates)
+     * @throws ArrayIndexOutOfBoundsException if {@code sequence} encoded in UTF-8 is longer than
+     *     {@code bytes.length - offset}
+     * @return the new offset, equivalent to {@code offset + Utf8.encodedLength(sequence)}
+     */
+    abstract int encodeUtf8(CharSequence in, byte[] out, int offset, int length);
+
+    /**
+     * Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}).
+     * Upon returning from this method, the {@code out} position will point to the position after
+     * the last encoded byte. This method requires paired surrogates, and therefore does not
+     * support chunking.
+     *
+     * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+     * compute the exact amount needed, or leave room for
+     * {@code Utf8.MAX_BYTES_PER_CHAR * in.length()}, which is the largest possible number
+     * of bytes that any input can be encoded to.
+     *
+     * @param in the source character sequence to be encoded
+     * @param out the target buffer
+     * @throws UnpairedSurrogateException if {@code in} contains ill-formed UTF-16 (unpaired
+     *     surrogates)
+     * @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than
+     *     {@code out.remaining()}
+     */
+    final void encodeUtf8(CharSequence in, ByteBuffer out) {
+      if (out.hasArray()) {
+        final int offset = out.arrayOffset();
+        int endIndex =
+            Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
+        out.position(endIndex - offset);
+      } else if (out.isDirect()) {
+        encodeUtf8Direct(in, out);
+      } else {
+        encodeUtf8Default(in, out);
+      }
+    }
+
+    /**
+     * Encodes the input character sequence to a direct {@link ByteBuffer} instance.
+     */
+    abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out);
+
+    /**
+     * Encodes the input character sequence to a {@link ByteBuffer} instance using the {@link
+     * ByteBuffer} API, rather than potentially faster approaches.
+     */
+    final void encodeUtf8Default(CharSequence in, ByteBuffer out) {
+      final int inLength = in.length();
+      int outIx = out.position();
+      int inIx = 0;
+
+      // Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check
+      // access. Assume the buffer is big enough and let it handle the out of bounds exception
+      // if it occurs.
+      try {
+        // Designed to take advantage of
+        // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+        for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+          out.put(outIx + inIx, (byte) c);
+        }
+        if (inIx == inLength) {
+          // Successfully encoded the entire string.
+          out.position(outIx + inIx);
+          return;
+        }
+
+        outIx += inIx;
+        for (char c; inIx < inLength; ++inIx, ++outIx) {
+          c = in.charAt(inIx);
+          if (c < 0x80) {
+            // One byte (0xxx xxxx)
+            out.put(outIx, (byte) c);
+          } else if (c < 0x800) {
+            // Two bytes (110x xxxx 10xx xxxx)
+
+            // Benchmarks show put performs better than putShort here (for HotSpot).
+            out.put(outIx++, (byte) (0xC0 | (c >>> 6)));
+            out.put(outIx, (byte) (0x80 | (0x3F & c)));
+          } else if (c < MIN_SURROGATE || MAX_SURROGATE < c) {
+            // Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
+            // Maximum single-char code point is 0xFFFF, 16 bits.
+
+            // Benchmarks show put performs better than putShort here (for HotSpot).
+            out.put(outIx++, (byte) (0xE0 | (c >>> 12)));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+            out.put(outIx, (byte) (0x80 | (0x3F & c)));
+          } else {
+            // Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx)
+
+            // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+            // bytes
+            final char low;
+            if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+              throw new UnpairedSurrogateException(inIx, inLength);
+            }
+            // TODO(nathanmittler): Consider using putInt() to improve performance.
+            int codePoint = toCodePoint(c, low);
+            out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+            out.put(outIx, (byte) (0x80 | (0x3F & codePoint)));
+          }
+        }
+
+        // Successfully encoded the entire string.
+        out.position(outIx);
+      } catch (IndexOutOfBoundsException e) {
+        // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
+
+        // If we failed in the outer ASCII loop, outIx will not have been updated. In this case,
+        // use inIx to determine the bad write index.
+        int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1);
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex);
+      }
+    }
+  }
+
+  /**
+   * {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods.
+   */
+  static final class SafeProcessor extends Processor {
+    @Override
+    int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (index >= limit) {  // No bytes? No progress.
+          return state;
+        }
+        int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(bytes, index, limit);
+    }
+
+    @Override
+    int partialIsValidUtf8Direct(int state, ByteBuffer buffer, int index, int limit) {
+      // For safe processing, we have to use the ByteBuffer API.
+      return partialIsValidUtf8Default(state, buffer, index, limit);
+    }
+
+    @Override
+    String decodeUtf8(byte[] bytes, int index, int size) throws InvalidProtocolBufferException {
+      // Bitwise OR combines the sign bits so any negative value fails the check.
+      if ((index | size | bytes.length - index - size) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
+      }
+
+      int offset = index;
+      final int limit = offset + size;
+
+      // The longest possible resulting String is the same as the number of input bytes, when it is
+      // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+      char[] resultArr = new char[size];
+      int resultPos = 0;
+
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (offset < limit) {
+        byte b = bytes[offset];
+        if (!DecodeUtil.isOneByte(b)) {
+          break;
+        }
+        offset++;
+        DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+      }
+
+      while (offset < limit) {
+        byte byte1 = bytes[offset++];
+        if (DecodeUtil.isOneByte(byte1)) {
+          DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+          // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+          // extra optimized loop to take care of these runs.
+          while (offset < limit) {
+            byte b = bytes[offset];
+            if (!DecodeUtil.isOneByte(b)) {
+              break;
+            }
+            offset++;
+            DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+          }
+        } else if (DecodeUtil.isTwoBytes(byte1)) {
+          if (offset >= limit) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleTwoBytes(byte1, /* byte2 */ bytes[offset++], resultArr, resultPos++);
+        } else if (DecodeUtil.isThreeBytes(byte1)) {
+          if (offset >= limit - 1) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleThreeBytes(
+              byte1,
+              /* byte2 */ bytes[offset++],
+              /* byte3 */ bytes[offset++],
+              resultArr,
+              resultPos++);
+        } else {
+          if (offset >= limit - 2) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleFourBytes(
+              byte1,
+              /* byte2 */ bytes[offset++],
+              /* byte3 */ bytes[offset++],
+              /* byte4 */ bytes[offset++],
+              resultArr,
+              resultPos++);
+          // 4-byte case requires two chars.
+          resultPos++;
+        }
+      }
+
+      return new String(resultArr, 0, resultPos);
+    }
+
+    @Override
+    String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+        throws InvalidProtocolBufferException {
+      // For safe processing, we have to use the ByteBufferAPI.
+      return decodeUtf8Default(buffer, index, size);
+    }
+
+    @Override
+    int encodeUtf8(CharSequence in, byte[] out, int offset, int length) {
+      int utf16Length = in.length();
+      int j = offset;
+      int i = 0;
+      int limit = offset + length;
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) {
+        out[j + i] = (byte) c;
+      }
+      if (i == utf16Length) {
+        return j + utf16Length;
+      }
+      j += i;
+      for (char c; i < utf16Length; i++) {
+        c = in.charAt(i);
+        if (c < 0x80 && j < limit) {
+          out[j++] = (byte) c;
+        } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+          out[j++] = (byte) ((0xF << 6) | (c >>> 6));
+          out[j++] = (byte) (0x80 | (0x3F & c));
+        } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          out[j++] = (byte) ((0xF << 5) | (c >>> 12));
+          out[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+          out[j++] = (byte) (0x80 | (0x3F & c));
+        } else if (j <= limit - 4) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
+          // four UTF-8 bytes
+          final char low;
+          if (i + 1 == in.length()
+                  || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
+            throw new UnpairedSurrogateException((i - 1), utf16Length);
+          }
+          int codePoint = Character.toCodePoint(c, low);
+          out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+          out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+          out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+          out[j++] = (byte) (0x80 | (0x3F & codePoint));
+        } else {
+          // If we are surrogates and we're not a surrogate pair, always throw an
+          // UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
+          if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
+              && (i + 1 == in.length()
+                  || !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
+            throw new UnpairedSurrogateException(i, utf16Length);
+          }
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+        }
+      }
+      return j;
+    }
+
+    @Override
+    void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+      // For safe processing, we have to use the ByteBuffer API.
+      encodeUtf8Default(in, out);
+    }
+
+    private static int partialIsValidUtf8(byte[] bytes, int index, int limit) {
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (index < limit && bytes[index] >= 0) {
+        index++;
+      }
+
+      return (index >= limit) ? COMPLETE : partialIsValidUtf8NonAscii(bytes, index, limit);
+    }
+
+    private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) {
+      for (;;) {
+        int byte1, byte2;
+
+        // Optimize for interior runs of ASCII bytes.
+        do {
+          if (index >= limit) {
+            return COMPLETE;
+          }
+        } while ((byte1 = bytes[index++]) >= 0);
+
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          if (index >= limit) {
+            // Incomplete sequence
+            return byte1;
+          }
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          if (index >= limit - 1) { // incomplete sequence
+            return incompleteStateFor(bytes, index, limit);
+          }
+          if ((byte2 = bytes[index++]) > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          if (index >= limit - 2) {  // incomplete sequence
+            return incompleteStateFor(bytes, index, limit);
+          }
+          if ((byte2 = bytes[index++]) > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF
+              // byte4 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
+   */
+  static final class UnsafeProcessor extends Processor {
+    /**
+     * Indicates whether or not all required unsafe operations are supported on this platform.
+     */
+    static boolean isAvailable() {
+      return hasUnsafeArrayOperations() && hasUnsafeByteBufferOperations();
+    }
+
+    @Override
+    int partialIsValidUtf8(int state, byte[] bytes, final int index, final int limit) {
+      // Bitwise OR combines the sign bits so any negative value fails the check.
+      if ((index | limit | bytes.length - limit) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
+      }
+      long offset = index;
+      final long offsetLimit = limit;
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (offset >= offsetLimit) {  // No bytes? No progress.
+          return state;
+        }
+        int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = UnsafeUtil.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = UnsafeUtil.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = UnsafeUtil.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(bytes, offset, (int) (offsetLimit - offset));
+    }
+
+    @Override
+    int partialIsValidUtf8Direct(
+        final int state, ByteBuffer buffer, final int index, final int limit) {
+      // Bitwise OR combines the sign bits so any negative value fails the check.
+      if ((index | limit | buffer.limit() - limit) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, limit));
+      }
+      long address = addressOffset(buffer) + index;
+      final long addressLimit = address + (limit - index);
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (address >= addressLimit) { // No bytes? No progress.
+          return state;
+        }
+
+        final int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = UnsafeUtil.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = UnsafeUtil.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = UnsafeUtil.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(address, (int) (addressLimit - address));
+    }
+
+    @Override
+    String decodeUtf8(byte[] bytes, int index, int size) throws InvalidProtocolBufferException {
+      if ((index | size | bytes.length - index - size) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
+      }
+
+      int offset = index;
+      final int limit = offset + size;
+
+      // The longest possible resulting String is the same as the number of input bytes, when it is
+      // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+      char[] resultArr = new char[size];
+      int resultPos = 0;
+
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (offset < limit) {
+        byte b = UnsafeUtil.getByte(bytes, offset);
+        if (!DecodeUtil.isOneByte(b)) {
+          break;
+        }
+        offset++;
+        DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+      }
+
+      while (offset < limit) {
+        byte byte1 = UnsafeUtil.getByte(bytes, offset++);
+        if (DecodeUtil.isOneByte(byte1)) {
+          DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+          // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+          // extra optimized loop to take care of these runs.
+          while (offset < limit) {
+            byte b = UnsafeUtil.getByte(bytes, offset);
+            if (!DecodeUtil.isOneByte(b)) {
+              break;
+            }
+            offset++;
+            DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+          }
+        } else if (DecodeUtil.isTwoBytes(byte1)) {
+          if (offset >= limit) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleTwoBytes(
+              byte1, /* byte2 */ UnsafeUtil.getByte(bytes, offset++), resultArr, resultPos++);
+        } else if (DecodeUtil.isThreeBytes(byte1)) {
+          if (offset >= limit - 1) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleThreeBytes(
+              byte1,
+              /* byte2 */ UnsafeUtil.getByte(bytes, offset++),
+              /* byte3 */ UnsafeUtil.getByte(bytes, offset++),
+              resultArr,
+              resultPos++);
+        } else {
+          if (offset >= limit - 2) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleFourBytes(
+              byte1,
+              /* byte2 */ UnsafeUtil.getByte(bytes, offset++),
+              /* byte3 */ UnsafeUtil.getByte(bytes, offset++),
+              /* byte4 */ UnsafeUtil.getByte(bytes, offset++),
+              resultArr,
+              resultPos++);
+          // 4-byte case requires two chars.
+          resultPos++;
+        }
+      }
+
+      if (resultPos < resultArr.length) {
+        resultArr = Arrays.copyOf(resultArr, resultPos);
+      }
+      return UnsafeUtil.moveToString(resultArr);
+    }
+
+    @Override
+    String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
+        throws InvalidProtocolBufferException {
+      // Bitwise OR combines the sign bits so any negative value fails the check.
+      if ((index | size | buffer.limit() - index - size) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, size));
+      }
+      long address = UnsafeUtil.addressOffset(buffer) + index;
+      final long addressLimit = address + size;
+
+      // The longest possible resulting String is the same as the number of input bytes, when it is
+      // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+      char[] resultArr = new char[size];
+      int resultPos = 0;
+
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (address < addressLimit) {
+        byte b = UnsafeUtil.getByte(address);
+        if (!DecodeUtil.isOneByte(b)) {
+          break;
+        }
+        address++;
+        DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+      }
+
+      while (address < addressLimit) {
+        byte byte1 = UnsafeUtil.getByte(address++);
+        if (DecodeUtil.isOneByte(byte1)) {
+          DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+          // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+          // extra optimized loop to take care of these runs.
+          while (address < addressLimit) {
+            byte b = UnsafeUtil.getByte(address);
+            if (!DecodeUtil.isOneByte(b)) {
+              break;
+            }
+            address++;
+            DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+          }
+        } else if (DecodeUtil.isTwoBytes(byte1)) {
+          if (address >= addressLimit) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleTwoBytes(
+              byte1, /* byte2 */ UnsafeUtil.getByte(address++), resultArr, resultPos++);
+        } else if (DecodeUtil.isThreeBytes(byte1)) {
+          if (address >= addressLimit - 1) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleThreeBytes(
+              byte1,
+              /* byte2 */ UnsafeUtil.getByte(address++),
+              /* byte3 */ UnsafeUtil.getByte(address++),
+              resultArr,
+              resultPos++);
+        } else {
+          if (address >= addressLimit - 2) {
+            throw InvalidProtocolBufferException.invalidUtf8();
+          }
+          DecodeUtil.handleFourBytes(
+              byte1,
+              /* byte2 */ UnsafeUtil.getByte(address++),
+              /* byte3 */ UnsafeUtil.getByte(address++),
+              /* byte4 */ UnsafeUtil.getByte(address++),
+              resultArr,
+              resultPos++);
+          // 4-byte case requires two chars.
+          resultPos++;
+        }
+      }
+
+      if (resultPos < resultArr.length) {
+        resultArr = Arrays.copyOf(resultArr, resultPos);
+      }
+      return UnsafeUtil.moveToString(resultArr);
+    }
+
+    @Override
+    int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
+      long outIx = offset;
+      final long outLimit = outIx + length;
+      final int inLimit = in.length();
+      if (inLimit > length || out.length - length < offset) {
+        // Not even enough room for an ASCII-encoded string.
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inLimit - 1) + " at index " + (offset + length));
+      }
+
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      int inIx = 0;
+      for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+        UnsafeUtil.putByte(out, outIx++, (byte) c);
+      }
+      if (inIx == inLimit) {
+        // We're done, it was ASCII encoded.
+        return (int) outIx;
+      }
+
+      for (char c; inIx < inLimit; ++inIx) {
+        c = in.charAt(inIx);
+        if (c < 0x80 && outIx < outLimit) {
+          UnsafeUtil.putByte(out, outIx++, (byte) c);
+        } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if (outIx <= outLimit - 4L) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+          // bytes
+          final char low;
+          if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+            throw new UnpairedSurrogateException((inIx - 1), inLimit);
+          }
+          int codePoint = toCodePoint(c, low);
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
+        } else {
+          if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+              && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+            // We are surrogates and we're not a surrogate pair.
+            throw new UnpairedSurrogateException(inIx, inLimit);
+          }
+          // Not enough space in the output buffer.
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+        }
+      }
+
+      // All bytes have been encoded.
+      return (int) outIx;
+    }
+
+    @Override
+    void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+      final long address = addressOffset(out);
+      long outIx = address + out.position();
+      final long outLimit = address + out.limit();
+      final int inLimit = in.length();
+      if (inLimit > outLimit - outIx) {
+        // Not even enough room for an ASCII-encoded string.
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inLimit - 1) + " at index " + out.limit());
+      }
+
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      int inIx = 0;
+      for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+        UnsafeUtil.putByte(outIx++, (byte) c);
+      }
+      if (inIx == inLimit) {
+        // We're done, it was ASCII encoded.
+        out.position((int) (outIx - address));
+        return;
+      }
+
+      for (char c; inIx < inLimit; ++inIx) {
+        c = in.charAt(inIx);
+        if (c < 0x80 && outIx < outLimit) {
+          UnsafeUtil.putByte(outIx++, (byte) c);
+        } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if (outIx <= outLimit - 4L) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+          // bytes
+          final char low;
+          if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+            throw new UnpairedSurrogateException((inIx - 1), inLimit);
+          }
+          int codePoint = toCodePoint(c, low);
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
+        } else {
+          if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+              && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+            // We are surrogates and we're not a surrogate pair.
+            throw new UnpairedSurrogateException(inIx, inLimit);
+          }
+          // Not enough space in the output buffer.
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+        }
+      }
+
+      // All bytes have been encoded.
+      out.position((int) (outIx - address));
+    }
+
+    /**
+     * Counts (approximately) the number of consecutive ASCII characters starting from the given
+     * position, using the most efficient method available to the platform.
+     *
+     * @param bytes the array containing the character sequence
+     * @param offset the offset position of the index (same as index + arrayBaseOffset)
+     * @param maxChars the maximum number of characters to count
+     * @return the number of ASCII characters found. The stopping position will be at or
+     * before the first non-ASCII byte.
+     */
+    private static int unsafeEstimateConsecutiveAscii(
+        byte[] bytes, long offset, final int maxChars) {
+      if (maxChars < UNSAFE_COUNT_ASCII_THRESHOLD) {
+        // Don't bother with small strings.
+        return 0;
+      }
+
+      for (int i = 0; i < maxChars; i++) {
+        if (UnsafeUtil.getByte(bytes, offset++) < 0) {
+          return i;
+        }
+      }
+      return maxChars;
+    }
+
+    /**
+     * Same as {@link Utf8#estimateConsecutiveAscii(ByteBuffer, int, int)} except that it uses the
+     * most efficient method available to the platform.
+     */
+    private static int unsafeEstimateConsecutiveAscii(long address, final int maxChars) {
+      int remaining = maxChars;
+      if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+        // Don't bother with small strings.
+        return 0;
+      }
+
+      // Read bytes until 8-byte aligned so that we can read longs in the loop below.
+      // We do this by ANDing the address with 7 to determine the number of bytes that need to
+      // be read before we're 8-byte aligned.
+      final int unaligned = 8 - ((int) address & 7);
+      for (int j = unaligned; j > 0; j--) {
+        if (UnsafeUtil.getByte(address++) < 0) {
+          return unaligned - j;
+        }
+      }
+
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      // To speed things up further, we're reading longs instead of bytes so we use a mask to
+      // determine if any byte in the current long is non-ASCII.
+      remaining -= unaligned;
+      for (; remaining >= 8 && (UnsafeUtil.getLong(address) & ASCII_MASK_LONG) == 0;
+          address += 8, remaining -= 8) {}
+      return maxChars - remaining;
+    }
+
+    private static int partialIsValidUtf8(final byte[] bytes, long offset, int remaining) {
+      // Skip past ASCII characters as quickly as possible. 
+      final int skipped = unsafeEstimateConsecutiveAscii(bytes, offset, remaining);
+      remaining -= skipped;
+      offset += skipped;
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1 = 0;
+        for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(bytes, offset++)) >= 0; --remaining) {
+        }
+        if (remaining == 0) {
+          return COMPLETE;
+        }
+        remaining--;
+
+        // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form (110xxxxx 10xxxxxx)
+          if (remaining == 0) {
+            // Incomplete sequence
+            return byte1;
+          }
+          remaining--;
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+          if (remaining < 2) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+          }
+          remaining -= 2;
+
+          final int byte2;
+          if ((byte2 = UnsafeUtil.getByte(bytes, offset++)) > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+          if (remaining < 3) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+          }
+          remaining -= 3;
+
+          final int byte2;
+          if ((byte2 = UnsafeUtil.getByte(bytes, offset++)) > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    private static int partialIsValidUtf8(long address, int remaining) {
+      // Skip past ASCII characters as quickly as possible.
+      final int skipped = unsafeEstimateConsecutiveAscii(address, remaining);
+      address += skipped;
+      remaining -= skipped;
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1 = 0;
+        for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(address++)) >= 0; --remaining) {
+        }
+        if (remaining == 0) {
+          return COMPLETE;
+        }
+        remaining--;
+
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form
+
+          if (remaining == 0) {
+            // Incomplete sequence
+            return byte1;
+          }
+          remaining--;
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2 || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form
+
+          if (remaining < 2) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(address, byte1, remaining);
+          }
+          remaining -= 2;
+
+          final byte byte2 = UnsafeUtil.getByte(address++);
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // Four-byte form
+
+          if (remaining < 3) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(address, byte1, remaining);
+          }
+          remaining -= 3;
+
+          final byte byte2 = UnsafeUtil.getByte(address++);
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    private static int unsafeIncompleteStateFor(byte[] bytes, int byte1, long offset,
+        int remaining) {
+      switch (remaining) {
+        case 0: {
+          return incompleteStateFor(byte1);
+        }
+        case 1: {
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset));
+        }
+        case 2: {
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset),
+              UnsafeUtil.getByte(bytes, offset + 1));
+        }
+        default: {
+          throw new AssertionError();
+        }
+      }
+    }
+
+    private static int unsafeIncompleteStateFor(long address, final int byte1, int remaining) {
+      switch (remaining) {
+        case 0: {
+          return incompleteStateFor(byte1);
+        }
+        case 1: {
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(address));
+        }
+        case 2: {
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(address),
+              UnsafeUtil.getByte(address + 1));
+        }
+        default: {
+          throw new AssertionError();
+        }
+      }
+    }
+  }
+
+  /**
+   * Utility methods for decoding bytes into {@link String}. Callers are responsible for extracting
+   * bytes (possibly using Unsafe methods), and checking remaining bytes. All other UTF-8 validity
+   * checks and codepoint conversion happen in this class.
+   */
+  private static class DecodeUtil {
+
+    /**
+     * Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
+     */
+    private static boolean isOneByte(byte b) {
+      return b >= 0;
+    }
+
+    /**
+     * Returns whether this is a two-byte codepoint with the form '10XXXXXX'.
+     */
+    private static boolean isTwoBytes(byte b) {
+      return b < (byte) 0xE0;
+    }
+
+    /**
+     * Returns whether this is a three-byte codepoint with the form '110XXXXX'.
+     */
+    private static boolean isThreeBytes(byte b) {
+      return b < (byte) 0xF0;
+    }
+
+    private static void handleOneByte(byte byte1, char[] resultArr, int resultPos) {
+      resultArr[resultPos] = (char) byte1;
+    }
+
+    private static void handleTwoBytes(
+        byte byte1, byte byte2, char[] resultArr, int resultPos)
+        throws InvalidProtocolBufferException {
+      // Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
+      // overlong 2-byte, '11000001'.
+      if (byte1 < (byte) 0xC2
+          || isNotTrailingByte(byte2)) {
+        throw InvalidProtocolBufferException.invalidUtf8();
+      }
+      resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));
+    }
+
+    private static void handleThreeBytes(
+        byte byte1, byte byte2, byte byte3, char[] resultArr, int resultPos)
+        throws InvalidProtocolBufferException {
+      if (isNotTrailingByte(byte2)
+          // overlong? 5 most significant bits must not all be zero
+          || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+          // check for illegal surrogate codepoints
+          || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+          || isNotTrailingByte(byte3)) {
+        throw InvalidProtocolBufferException.invalidUtf8();
+      }
+      resultArr[resultPos] = (char)
+          (((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
+    }
+
+    private static void handleFourBytes(
+        byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr, int resultPos)
+        throws InvalidProtocolBufferException{
+      if (isNotTrailingByte(byte2)
+          // Check that 1 <= plane <= 16.  Tricky optimized form of:
+          //   valid 4-byte leading byte?
+          // if (byte1 > (byte) 0xF4 ||
+          //   overlong? 4 most significant bits must not all be zero
+          //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+          //   codepoint larger than the highest code point (U+10FFFF)?
+          //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+          || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+          || isNotTrailingByte(byte3)
+          || isNotTrailingByte(byte4)) {
+        throw InvalidProtocolBufferException.invalidUtf8();
+      }
+      int codepoint = ((byte1 & 0x07) << 18)
+          | (trailingByteValue(byte2) << 12)
+          | (trailingByteValue(byte3) << 6)
+          | trailingByteValue(byte4);
+      resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);
+      resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);
+    }
+
+    /**
+     * Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
+     */
+    private static boolean isNotTrailingByte(byte b) {
+      return b > (byte) 0xBF;
+    }
+
+    /**
+     * Returns the actual value of the trailing byte (removes the prefix '10') for composition.
+     */
+    private static int trailingByteValue(byte b) {
+      return b & 0x3F;
+    }
+
+    private static char highSurrogate(int codePoint) {
+      return (char) ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))
+          + (codePoint >>> 10));
+    }
+
+    private static char lowSurrogate(int codePoint) {
+      return (char) (MIN_LOW_SURROGATE + (codePoint & 0x3ff));
+    }
+  }
+
+  private Utf8() {}
 }
diff --git a/java/core/src/main/java/com/google/protobuf/WireFormat.java b/java/core/src/main/java/com/google/protobuf/WireFormat.java
index 8dbe1ae..8b837ee 100644
--- a/java/core/src/main/java/com/google/protobuf/WireFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java
@@ -47,6 +47,12 @@
   // Do not allow instantiation.
   private WireFormat() {}
 
+  static final int FIXED32_SIZE = 4;
+  static final int FIXED64_SIZE = 8;
+  static final int MAX_VARINT32_SIZE = 5;
+  static final int MAX_VARINT64_SIZE = 10;
+  static final int MAX_VARINT_SIZE = 10;
+
   public static final int WIRETYPE_VARINT           = 0;
   public static final int WIRETYPE_FIXED64          = 1;
   public static final int WIRETYPE_LENGTH_DELIMITED = 2;
@@ -116,16 +122,24 @@
     FIXED32 (JavaType.INT        , WIRETYPE_FIXED32         ),
     BOOL    (JavaType.BOOLEAN    , WIRETYPE_VARINT          ),
     STRING  (JavaType.STRING     , WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
+      @Override
+      public boolean isPackable() {
+        return false; }
     },
     GROUP   (JavaType.MESSAGE    , WIRETYPE_START_GROUP     ) {
-      public boolean isPackable() { return false; }
+      @Override
+      public boolean isPackable() {
+        return false; }
     },
     MESSAGE (JavaType.MESSAGE    , WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
+      @Override
+      public boolean isPackable() {
+        return false; }
     },
     BYTES   (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
+      @Override
+      public boolean isPackable() {
+        return false; }
     },
     UINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
     ENUM    (JavaType.ENUM       , WIRETYPE_VARINT          ),
@@ -170,18 +184,21 @@
   enum Utf8Validation {
     /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
     LOOSE {
+      @Override
       Object readString(CodedInputStream input) throws IOException {
         return input.readString();
       }
     },
     /** Eagerly parses to String; throws an IOException on invalid bytes. */
     STRICT {
+      @Override
       Object readString(CodedInputStream input) throws IOException {
         return input.readStringRequireUtf8();
       }
     },
     /** Keep data as ByteString; validation/conversion to String is lazy. */
     LAZY {
+      @Override
       Object readString(CodedInputStream input) throws IOException {
         return input.readBytes();
       }
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 d964ef5..cb2d34e 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,9 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestProto;
@@ -40,10 +43,8 @@
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestRequiredForeign;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-
-import junit.framework.TestCase;
-
 import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link AbstractMessage}.
@@ -65,35 +66,44 @@
       this.wrappedMessage = wrappedMessage;
     }
 
+    @Override
     public Descriptors.Descriptor getDescriptorForType() {
       return wrappedMessage.getDescriptorForType();
     }
+    @Override
     public AbstractMessageWrapper getDefaultInstanceForType() {
       return new AbstractMessageWrapper(
         wrappedMessage.getDefaultInstanceForType());
     }
+    @Override
     public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
       return wrappedMessage.getAllFields();
     }
+    @Override
     public boolean hasField(Descriptors.FieldDescriptor field) {
       return wrappedMessage.hasField(field);
     }
+    @Override
     public Object getField(Descriptors.FieldDescriptor field) {
       return wrappedMessage.getField(field);
     }
+    @Override
     public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
       return wrappedMessage.getRepeatedFieldCount(field);
     }
-    public Object getRepeatedField(
-        Descriptors.FieldDescriptor field, int index) {
+    @Override
+    public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
       return wrappedMessage.getRepeatedField(field, index);
     }
+    @Override
     public UnknownFieldSet getUnknownFields() {
       return wrappedMessage.getUnknownFields();
     }
+    @Override
     public Builder newBuilderForType() {
       return new Builder(wrappedMessage.newBuilderForType());
     }
+    @Override
     public Builder toBuilder() {
       return new Builder(wrappedMessage.toBuilder());
     }
@@ -105,65 +115,80 @@
         this.wrappedBuilder = wrappedBuilder;
       }
 
+      @Override
       public AbstractMessageWrapper build() {
         return new AbstractMessageWrapper(wrappedBuilder.build());
       }
+      @Override
       public AbstractMessageWrapper buildPartial() {
         return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
       }
+      @Override
       public Builder clone() {
         return new Builder(wrappedBuilder.clone());
       }
+      @Override
       public boolean isInitialized() {
         return clone().buildPartial().isInitialized();
       }
+      @Override
       public Descriptors.Descriptor getDescriptorForType() {
         return wrappedBuilder.getDescriptorForType();
       }
+      @Override
       public AbstractMessageWrapper getDefaultInstanceForType() {
         return new AbstractMessageWrapper(
           wrappedBuilder.getDefaultInstanceForType());
       }
+      @Override
       public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
         return wrappedBuilder.getAllFields();
       }
+      @Override
       public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
         return new Builder(wrappedBuilder.newBuilderForField(field));
       }
+      @Override
       public boolean hasField(Descriptors.FieldDescriptor field) {
         return wrappedBuilder.hasField(field);
       }
+      @Override
       public Object getField(Descriptors.FieldDescriptor field) {
         return wrappedBuilder.getField(field);
       }
+      @Override
       public Builder setField(Descriptors.FieldDescriptor field, Object value) {
         wrappedBuilder.setField(field, value);
         return this;
       }
+      @Override
       public Builder clearField(Descriptors.FieldDescriptor field) {
         wrappedBuilder.clearField(field);
         return this;
       }
+      @Override
       public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
         return wrappedBuilder.getRepeatedFieldCount(field);
       }
-      public Object getRepeatedField(
-          Descriptors.FieldDescriptor field, int index) {
+      @Override
+      public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
         return wrappedBuilder.getRepeatedField(field, index);
       }
-      public Builder setRepeatedField(Descriptors.FieldDescriptor field,
-                                      int index, Object value) {
+      @Override
+      public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) {
         wrappedBuilder.setRepeatedField(field, index, value);
         return this;
       }
-      public Builder addRepeatedField(
-          Descriptors.FieldDescriptor field, Object value) {
+      @Override
+      public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
         wrappedBuilder.addRepeatedField(field, value);
         return this;
       }
+      @Override
       public UnknownFieldSet getUnknownFields() {
         return wrappedBuilder.getUnknownFields();
       }
+      @Override
       public Builder setUnknownFields(UnknownFieldSet unknownFields) {
         wrappedBuilder.setUnknownFields(unknownFields);
         return this;
@@ -173,6 +198,7 @@
         return wrappedBuilder.getFieldBuilder(field);
       }
     }
+    @Override
     public Parser<? extends Message> getParserForType() {
       return wrappedMessage.getParserForType();
     }
@@ -323,11 +349,6 @@
   // -----------------------------------------------------------------
   // Tests for isInitialized().
 
-  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
-    TestRequired.getDefaultInstance();
-  private static final TestRequired TEST_REQUIRED_INITIALIZED =
-    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
-
   public void testIsInitialized() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
     AbstractMessageWrapper.Builder abstractBuilder =
@@ -357,7 +378,7 @@
     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
     assertFalse(abstractBuilder.isInitialized());
     assertEquals(
-        "optional_message.a, optional_message.b, optional_message.c",
+        "optional_message.b, optional_message.c",
         abstractBuilder.getInitializationErrorString());
 
     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
@@ -367,7 +388,7 @@
     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
     assertFalse(abstractBuilder.isInitialized());
     assertEquals(
-        "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+        "repeated_message[0].b, repeated_message[0].c",
         abstractBuilder.getInitializationErrorString());
 
     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
@@ -468,7 +489,6 @@
     checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
   }
 
-
   /**
    * Asserts that the given proto has symmetric equals and hashCode methods.
    */
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 e169f69..cf91ed9 100644
--- a/java/core/src/test/java/com/google/protobuf/AnyTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -75,6 +75,51 @@
     }
   }
 
+  public void testCustomTypeUrls() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    TestAny container = TestAny.newBuilder()
+        .setValue(Any.pack(message, "xxx.com")).build();
+
+    assertEquals(
+        "xxx.com/" + TestAllTypes.getDescriptor().getFullName(),
+        container.getValue().getTypeUrl());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    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());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+
+    container = TestAny.newBuilder()
+        .setValue(Any.pack(message, "")).build();
+
+    assertEquals(
+        "/" + TestAllTypes.getDescriptor().getFullName(),
+        container.getValue().getTypeUrl());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+  }
+
   public void testCachedUnpackResult() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
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 b8ad1fe..4906763 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -32,38 +32,39 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
+import com.google.protobuf.Internal.BooleanList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link BooleanArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class BooleanArrayListTest extends TestCase {
-  
-  private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
+
+  private static final BooleanArrayList UNARY_LIST =
+      newImmutableBooleanArrayList(true);
   private static final BooleanArrayList TERTIARY_LIST =
-      newImmutableBooleanArrayList(true, true, false);
-  
+      newImmutableBooleanArrayList(true, false, true);
+
   private BooleanArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new BooleanArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(BooleanArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
     list.addBoolean(true);
     list.addBoolean(false);
@@ -72,30 +73,16 @@
     list.makeImmutable();
     assertImmutable(list);
   }
-  
-  public void testCopyConstructor() {
-    BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
 
-    copy = new BooleanArrayList(BooleanArrayList.emptyList());
-    assertEquals(BooleanArrayList.emptyList(), copy);
-    
-    copy = new BooleanArrayList(asList(false, false, true));
-    assertEquals(asList(false, false, true), copy);
-
-    copy = new BooleanArrayList(Collections.<Boolean>emptyList());
-    assertEquals(BooleanArrayList.emptyList(), copy);
-  }
-  
   public void testModificationWithIteration() {
-    list.addAll(asList(true, false, false, true));
+    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());
     list.set(0, true);
     assertEquals(false, (boolean) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -103,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, false);
     try {
@@ -113,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(true, (boolean) TERTIARY_LIST.get(0));
-    assertEquals(true, (boolean) TERTIARY_LIST.get(1));
-    assertEquals(false, (boolean) TERTIARY_LIST.get(2));
-    
+    assertEquals(false, (boolean) TERTIARY_LIST.get(1));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -133,19 +120,19 @@
       // expected
     }
   }
-  
-  public void testGetInt() {
+
+  public void testGetBoolean() {
     assertEquals(true, TERTIARY_LIST.getBoolean(0));
-    assertEquals(true, TERTIARY_LIST.getBoolean(1));
-    assertEquals(false, TERTIARY_LIST.getBoolean(2));
-    
+    assertEquals(false, TERTIARY_LIST.getBoolean(1));
+    assertEquals(true, TERTIARY_LIST.getBoolean(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -153,7 +140,7 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, BooleanArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
@@ -164,26 +151,26 @@
     list.addBoolean(false);
     list.addBoolean(false);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
+
     list.add(true);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addBoolean(false);
     list.addBoolean(false);
-    
+
     assertEquals(false, (boolean) list.set(0, true));
     assertEquals(true, list.getBoolean(0));
 
     assertEquals(false, (boolean) list.set(1, false));
     assertEquals(false, list.getBoolean(1));
-    
+
     try {
-      list.set(-1, true);
+      list.set(-1, false);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
@@ -196,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetInt() {
+
+  public void testSetBoolean() {
     list.addBoolean(true);
     list.addBoolean(true);
-    
+
     assertEquals(true, list.setBoolean(0, false));
     assertEquals(false, list.getBoolean(0));
 
     assertEquals(true, list.setBoolean(1, false));
     assertEquals(false, list.getBoolean(1));
-    
+
     try {
       list.setBoolean(-1, false);
       fail();
@@ -215,76 +202,78 @@
     }
 
     try {
-      list.setBoolean(2, true);
+      list.setBoolean(2, false);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
-    assertTrue(list.add(true));
-    assertEquals(asList(true), list);
-
     assertTrue(list.add(false));
+    assertEquals(asList(false), list);
+
+    assertTrue(list.add(true));
     list.add(0, false);
-    assertEquals(asList(false, true, false), list);
-    
-    list.add(0, false);
+    assertEquals(asList(false, false, true), list);
+
     list.add(0, true);
+    list.add(0, false);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
-      list.add(true);
+      list.add(i % 2 == 0);
     }
-    assertEquals(asList(true, false, false, true, false, true, true, true, true, true, true), list);
-    
+    assertEquals(
+        asList(false, true, false, false, true, true, false, true, false, true, false),
+        list);
+
     try {
-      list.add(-1, false);
+      list.add(-1, true);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, true);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
-  public void testAddInt() {
+
+  public void testAddBoolean() {
     assertEquals(0, list.size());
 
-    list.addBoolean(true);
-    assertEquals(asList(true), list);
-
     list.addBoolean(false);
-    assertEquals(asList(true, false), list);
+    assertEquals(asList(false), list);
+
+    list.addBoolean(true);
+    assertEquals(asList(false, true), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
-    assertTrue(list.addAll(Collections.singleton(false)));
+    assertTrue(list.addAll(Collections.singleton(true)));
     assertEquals(1, list.size());
-    assertEquals(false, (boolean) list.get(0));
-    assertEquals(false, list.getBoolean(0));
-    
-    assertTrue(list.addAll(asList(true, false, false, false, true)));
-    assertEquals(asList(false, true, false, false, false, true), list);
-    
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, list.getBoolean(0));
+
+    assertTrue(list.addAll(asList(false, true, false, true, false)));
+    assertEquals(asList(true, false, true, false, true, false), list);
+
     assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(false, true, false, false, false, true, true, true, false), list);
+    assertEquals(asList(true, false, true, false, true, false, true, false, true), list);
 
     assertFalse(list.addAll(Collections.<Boolean>emptyList()));
     assertFalse(list.addAll(BooleanArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(true, (boolean) list.remove(0));
-    assertEquals(asList(true, false), list);
+    assertEquals(asList(false, true), list);
 
     assertTrue(list.remove(Boolean.TRUE));
     assertEquals(asList(false), list);
@@ -294,92 +283,107 @@
 
     assertEquals(false, (boolean) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
+  public void testRemoveEndOfCapacity() {
+    BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addBoolean(true);
+    toRemove.remove(0);
+    assertEquals(0, toRemove.size());
+  }
+
+  public void testSublistRemoveEndOfCapacity() {
+    BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addBoolean(true);
+    toRemove.subList(0, 1).clear();
+    assertEquals(0, toRemove.size());
+  }
+
   private void assertImmutable(BooleanArrayList list) {
+
     try {
-      list.add(false);
+      list.add(true);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, true);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.addAll(Collections.singletonList(false));
+      list.addAll(Collections.singletonList(true));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new BooleanArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(true));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.addBoolean(true);
+      list.addBoolean(false);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -393,63 +397,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.retainAll(Collections.singleton(Boolean.TRUE));
+      list.removeAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.set(0, true);
+      list.set(0, false);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setBoolean(0, false);
       fail();
@@ -457,7 +461,7 @@
       // expected
     }
   }
-  
+
   private static BooleanArrayList newImmutableBooleanArrayList(boolean... elements) {
     BooleanArrayList list = new BooleanArrayList();
     for (boolean element : elements) {
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 7a8a0a5..db10ee7 100644
--- a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -37,7 +37,6 @@
 import java.io.ObjectOutputStream;
 import java.io.UnsupportedEncodingException;
 
-
 /**
  * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
  * by inheriting the tests from {@link LiteralByteStringTest}.  The only method which
diff --git a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
new file mode 100644
index 0000000..6b1cfe7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
@@ -0,0 +1,80 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link ByteBufferWriter}.
+ */
+public class ByteBufferWriterTest extends TestCase {
+
+  public void testHeapBuffer() throws IOException {
+    // Test a small and large buffer.
+    testWrite(ByteBuffer.allocate(100));
+    testWrite(ByteBuffer.allocate(1024 * 100));
+  }
+
+  public void testDirectBuffer() throws IOException {
+    // Test a small and large buffer.
+    testWrite(ByteBuffer.allocateDirect(100));
+    testWrite(ByteBuffer.allocateDirect(1024 * 100));
+  }
+
+  private void testWrite(ByteBuffer buffer) throws IOException {
+    fillRandom(buffer);
+    ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.remaining());
+    ByteBufferWriter.write(buffer, os);
+    assertEquals(0, buffer.position());
+    assertTrue(Arrays.equals(toArray(buffer), os.toByteArray()));
+  }
+
+  private void fillRandom(ByteBuffer buf) {
+    byte[] bytes = new byte[buf.remaining()];
+    new Random().nextBytes(bytes);
+    buf.put(bytes);
+    buf.flip();
+    return;
+  }
+
+  private byte[] toArray(ByteBuffer buf) {
+    int originalPosition = buf.position();
+    byte[] bytes = new byte[buf.remaining()];
+    buf.get(bytes);
+    buf.position(originalPosition);
+    return bytes;
+  }
+}
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 5267c16..be71f1f 100644
--- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -31,14 +31,12 @@
 package com.google.protobuf;
 
 import com.google.protobuf.ByteString.Output;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.reflect.Field;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -47,6 +45,7 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Random;
+import junit.framework.TestCase;
 
 /**
  * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
@@ -757,4 +756,17 @@
     assertEquals((byte) 2, result[dataSize - dataSize / 2]);
     assertEquals((byte) 2, result[dataSize - 1]);
   }
+  
+  /**
+   * Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
+   */
+  public void testByteArrayCopier() throws Exception {
+    Field field = ByteString.class.getDeclaredField("byteArrayCopier");
+    field.setAccessible(true);
+    Object byteArrayCopier = field.get(null);
+    assertNotNull(byteArrayCopier);
+    assertTrue(
+        byteArrayCopier.toString(),
+        byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier"));
+  }
 }
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 3d6381c..50b87ae 100644
--- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -34,6 +34,7 @@
 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;
 
 /**
@@ -89,14 +90,9 @@
   }
 
   public void testParseRequiredStringWithBadUtf8() throws Exception {
-    ByteString serialized =
-        BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
-    try {
-      StringWrapper.parser().parseFrom(serialized);
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
-    }
+    byte[] serialized =
+        BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
+    assertParseBadUtf8(StringWrapper.getDefaultInstance(), serialized);
   }
 
   public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
@@ -127,14 +123,36 @@
   }
 
   public void testParseRequiredStringWithBadUtf8Size() throws Exception {
-    ByteString serialized =
-        BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+    byte[] serialized =
+        BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
+    assertParseBadUtf8(StringWrapperSize.getDefaultInstance(), serialized);
+  }
+
+  private void assertParseBadUtf8(MessageLite defaultInstance, byte[] data) throws Exception {
+    // Check combinations of (parser vs. builder) x (byte[] vs. InputStream)
     try {
-      StringWrapperSize.parser().parseFrom(serialized);
+      defaultInstance.getParserForType().parseFrom(data);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+    try {
+      defaultInstance.newBuilderForType().mergeFrom(data);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+    try {
+      defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data));
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+    try {
+      defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data));
       fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
     } catch (InvalidProtocolBufferException exception) {
       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
     }
   }
-
 }
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 18d8142..5ea6b79 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -35,15 +35,15 @@
 import protobuf_unittest.UnittestProto.Int64Message;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link CodedInputStream}.
@@ -51,10 +51,84 @@
  * @author kenton@google.com Kenton Varda
  */
 public class CodedInputStreamTest extends TestCase {
+  
+  private static final int DEFAULT_BLOCK_SIZE = 4096; 
+  
+  private enum InputType {
+    ARRAY {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(data);
+      }
+    },
+    NIO_HEAP {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(ByteBuffer.wrap(data));
+      }
+    },
+    NIO_DIRECT {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
+        buffer.put(data);
+        buffer.flip();
+        return CodedInputStream.newInstance(buffer);
+      }
+    },
+    STREAM {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        return CodedInputStream.newInstance(new SmallBlockInputStream(data, blockSize));
+      }
+    },
+    ITER_DIRECT {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        if (blockSize > DEFAULT_BLOCK_SIZE) {
+          blockSize = DEFAULT_BLOCK_SIZE;
+        }
+        ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+        for (int i = 0; i < data.length; i += blockSize) {
+          int rl = Math.min(blockSize, data.length - i); 
+          ByteBuffer rb = ByteBuffer.allocateDirect(rl); 
+          rb.put(data, i, rl);
+          rb.flip();
+          input.add(rb);
+        }
+        return CodedInputStream.newInstance(input);
+      }
+    },
+    STREAM_ITER_DIRECT {
+      @Override
+      CodedInputStream newDecoder(byte[] data, int blockSize) {
+        if (blockSize > DEFAULT_BLOCK_SIZE) {
+          blockSize = DEFAULT_BLOCK_SIZE;
+        }
+        ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+        for (int i = 0; i < data.length; i += blockSize) {
+          int rl = Math.min(blockSize, data.length - i); 
+          ByteBuffer rb = ByteBuffer.allocateDirect(rl); 
+          rb.put(data, i, rl);
+          rb.flip();
+          input.add(rb);
+        }
+        return CodedInputStream.newInstance(new IterableByteBufferInputStream(input));
+      }
+    };
+    
+    
+
+    CodedInputStream newDecoder(byte[] data) {
+      return newDecoder(data, data.length);
+    }
+
+    abstract CodedInputStream newDecoder(byte[] data, int blockSize);
+  }
+
   /**
-   * Helper to construct a byte array from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
+   * Helper to construct a byte array from a bunch of bytes. The inputs are actually ints so that I
+   * can use hex notation and not get stupid errors about precision.
    */
   private byte[] bytes(int... bytesAsInts) {
     byte[] bytes = new byte[bytesAsInts.length];
@@ -65,79 +139,58 @@
   }
 
   /**
-   * An InputStream which limits the number of bytes it reads at a time.
-   * We use this to make sure that CodedInputStream doesn't screw up when
-   * reading in small blocks.
+   * An InputStream which limits the number of bytes it reads at a time. We use this to make sure
+   * that CodedInputStream doesn't screw up when reading in small blocks.
    */
   private static final class SmallBlockInputStream extends FilterInputStream {
     private final int blockSize;
 
     public SmallBlockInputStream(byte[] data, int blockSize) {
-      this(new ByteArrayInputStream(data), blockSize);
-    }
-
-    public SmallBlockInputStream(InputStream in, int blockSize) {
-      super(in);
+      super(new ByteArrayInputStream(data));
       this.blockSize = blockSize;
     }
 
+    @Override
     public int read(byte[] b) throws IOException {
       return super.read(b, 0, Math.min(b.length, blockSize));
     }
 
+    @Override
     public int read(byte[] b, int off, int len) throws IOException {
       return super.read(b, off, Math.min(len, blockSize));
     }
   }
 
-  private void assertDataConsumed(byte[] data, CodedInputStream input)
+  private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
       throws IOException {
-    assertEquals(data.length, input.getTotalBytesRead());
-    assertTrue(input.isAtEnd());
+    assertEquals(msg, data.length, input.getTotalBytesRead());
+    assertTrue(msg, input.isAtEnd());
   }
 
   /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * checks that the result matches the given value.
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and checks that the result
+   * matches the given value.
    */
   private void assertReadVarint(byte[] data, long value) throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals((int) value, input.readRawVarint32());
-    assertDataConsumed(data, input);
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), (int) value, input.readRawVarint32());
+        assertDataConsumed(inputType.name(), data, input);
 
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64());
-    assertDataConsumed(data, input);
+        input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawVarint64());
+        assertDataConsumed(inputType.name(), data, input);
 
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64SlowPath());
-    assertDataConsumed(data, input);
+        input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawVarint64SlowPath());
+        assertDataConsumed(inputType.name(), data, input);
 
-    input = CodedInputStream.newInstance(data);
-    assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-    assertDataConsumed(data, input);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals((int) value, input.readRawVarint32());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64SlowPath());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-      assertDataConsumed(data, input);
+        input = inputType.newDecoder(data, blockSize);
+        assertTrue(inputType.name(), input.skipField(WireFormat.WIRETYPE_VARINT));
+        assertDataConsumed(inputType.name(), data, input);
+      }
     }
 
     // Try reading direct from an InputStream.  We want to verify that it
@@ -151,35 +204,26 @@
   }
 
   /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * expects them to fail with an InvalidProtocolBufferException whose
-   * description matches the given one.
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and expects them to fail
+   * with an InvalidProtocolBufferException whose description matches the given one.
    */
-  private void assertReadVarintFailure(
-      InvalidProtocolBufferException expected, byte[] data)
+  private void assertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)
       throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint32();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64SlowPath();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.readRawVarint32();
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+      }
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.readRawVarint64();
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
+      }
     }
 
     // Make sure we get the same error when reading direct from an InputStream.
@@ -199,72 +243,74 @@
     // 14882
     assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
     // 2961488830
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x0bL << 28));
+    assertReadVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
 
     // 64-bit
     // 7256456126
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x1bL << 28));
+    assertReadVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
     // 41256202580718336
     assertReadVarint(
-      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
-      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
-      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+        bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+        (0x00 << 0)
+            | (0x66 << 7)
+            | (0x6b << 14)
+            | (0x1c << 21)
+            | (0x43L << 28)
+            | (0x49L << 35)
+            | (0x24L << 42)
+            | (0x49L << 49));
     // 11964378330978735131
     assertReadVarint(
-      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
-      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
-      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
-      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+        bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+        (0x1b << 0)
+            | (0x28 << 7)
+            | (0x79 << 14)
+            | (0x42 << 21)
+            | (0x3bL << 28)
+            | (0x56L << 35)
+            | (0x00L << 42)
+            | (0x05L << 49)
+            | (0x26L << 56)
+            | (0x01L << 63));
 
     // Failures
     assertReadVarintFailure(
-      InvalidProtocolBufferException.malformedVarint(),
-      bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-            0x00));
-    assertReadVarintFailure(
-      InvalidProtocolBufferException.truncatedMessage(),
-      bytes(0x80));
+        InvalidProtocolBufferException.malformedVarint(),
+        bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00));
+    assertReadVarintFailure(InvalidProtocolBufferException.truncatedMessage(), bytes(0x80));
   }
 
   /**
-   * Parses the given bytes using readRawLittleEndian32() and checks
-   * that the result matches the given value.
+   * Parses the given bytes using readRawLittleEndian32() and checks that the result matches the
+   * given value.
    */
-  private void assertReadLittleEndian32(byte[] data, int value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian32());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian32());
-      assertTrue(input.isAtEnd());
+  private void assertReadLittleEndian32(byte[] data, int value) throws Exception {
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawLittleEndian32());
+        assertTrue(inputType.name(), input.isAtEnd());
+      }
     }
   }
 
   /**
-   * Parses the given bytes using readRawLittleEndian64() and checks
-   * that the result matches the given value.
+   * Parses the given bytes using readRawLittleEndian64() and checks that the result matches the
+   * given value.
    */
-  private void assertReadLittleEndian64(byte[] data, long value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian64());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian64());
-      assertTrue(input.isAtEnd());
+  private void assertReadLittleEndian64(byte[] data, long value) throws Exception {
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+        CodedInputStream input = inputType.newDecoder(data, blockSize);
+        assertEquals(inputType.name(), value, input.readRawLittleEndian64());
+        assertTrue(inputType.name(), input.isAtEnd());
+      }
     }
   }
 
@@ -274,40 +320,32 @@
     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
 
     assertReadLittleEndian64(
-      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
-      0x123456789abcdef0L);
+        bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
     assertReadLittleEndian64(
-      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
-      0x9abcdef012345678L);
+        bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
   }
 
   /** Test decodeZigZag32() and decodeZigZag64(). */
   public void testDecodeZigZag() throws Exception {
-    assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+    assertEquals(0, CodedInputStream.decodeZigZag32(0));
     assertEquals(-1, CodedInputStream.decodeZigZag32(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag32(2));
+    assertEquals(1, CodedInputStream.decodeZigZag32(2));
     assertEquals(-2, CodedInputStream.decodeZigZag32(3));
     assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
     assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
     assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
     assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
 
-    assertEquals( 0, CodedInputStream.decodeZigZag64(0));
+    assertEquals(0, CodedInputStream.decodeZigZag64(0));
     assertEquals(-1, CodedInputStream.decodeZigZag64(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag64(2));
+    assertEquals(1, CodedInputStream.decodeZigZag64(2));
     assertEquals(-2, CodedInputStream.decodeZigZag64(3));
-    assertEquals(0x000000003FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
-    assertEquals(0xFFFFFFFFC0000000L,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
-    assertEquals(0x000000007FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
-    assertEquals(0xFFFFFFFF80000000L,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
-    assertEquals(0x7FFFFFFFFFFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
-    assertEquals(0x8000000000000000L,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+    assertEquals(0x000000003FFFFFFFL, CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
+    assertEquals(0xFFFFFFFFC0000000L, CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
+    assertEquals(0x000000007FFFFFFFL, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
+    assertEquals(0xFFFFFFFF80000000L, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
+    assertEquals(0x7FFFFFFFFFFFFFFFL, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+    assertEquals(0x8000000000000000L, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
   }
 
   /** Tests reading and parsing a whole message with every field type. */
@@ -317,14 +355,12 @@
     byte[] rawBytes = message.toByteArray();
     assertEquals(rawBytes.length, message.getSerializedSize());
 
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-    TestUtil.assertAllFieldsSet(message2);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
-      message2 = TestAllTypes.parseFrom(
-        new SmallBlockInputStream(rawBytes, blockSize));
-      TestUtil.assertAllFieldsSet(message2);
+    for (InputType inputType : InputType.values()) {
+      // Try different block sizes.
+      for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+        TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(rawBytes, blockSize));
+        TestUtil.assertAllFieldsSet(message2);
+      }
     }
   }
 
@@ -333,57 +369,65 @@
     TestAllTypes message = TestUtil.getAllSet();
     byte[] rawBytes = message.toByteArray();
 
-    // Create two parallel inputs.  Parse one as unknown fields while using
-    // skipField() to skip each field on the other.  Expect the same tags.
-    CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
-    CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+    InputType[] inputTypes = InputType.values();
+    CodedInputStream[] inputs = new CodedInputStream[inputTypes.length];
+    for (int i = 0; i < inputs.length; ++i) {
+      inputs[i] = inputTypes[i].newDecoder(rawBytes);
+    }
     UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
 
     while (true) {
+      CodedInputStream input1 = inputs[0];
       int tag = input1.readTag();
-      assertEquals(tag, input2.readTag());
+      // Ensure that the rest match.
+      for (int i = 1; i < inputs.length; ++i) {
+        assertEquals(inputTypes[i].name(), tag, inputs[i].readTag());
+      }
       if (tag == 0) {
         break;
       }
       unknownFields.mergeFieldFrom(tag, input1);
-      input2.skipField(tag);
+      // Skip the field for the rest of the inputs.
+      for (int i = 1; i < inputs.length; ++i) {
+        inputs[i].skipField(tag);
+      }
     }
   }
 
 
   /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * exactly up to a limit, this should not break things.
+   * Test that a bug in skipRawBytes() has been fixed: if the skip skips exactly up to a limit, this
+   * should not break things.
    */
   public void testSkipRawBytesBug() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2 };
-    CodedInputStream input = CodedInputStream.newInstance(rawBytes);
-
-    int limit = input.pushLimit(1);
-    input.skipRawBytes(1);
-    input.popLimit(limit);
-    assertEquals(2, input.readRawByte());
+    byte[] rawBytes = new byte[] {1, 2};
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawBytes);
+      int limit = input.pushLimit(1);
+      input.skipRawBytes(1);
+      input.popLimit(limit);
+      assertEquals(inputType.name(), 2, input.readRawByte());
+    }
   }
 
   /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * past the end of a buffer with a limit that has been set past the end of
-   * that buffer, this should not break things.
+   * Test that a bug in skipRawBytes() has been fixed: if the skip skips past the end of a buffer
+   * with a limit that has been set past the end of that buffer, this should not break things.
    */
   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(rawBytes, 3));
-
-    int limit = input.pushLimit(4);
-    // In order to expose the bug we need to read at least one byte to prime the
-    // buffer inside the CodedInputStream.
-    assertEquals(1, input.readRawByte());
-    // Skip to the end of the limit.
-    input.skipRawBytes(3);
-    assertTrue(input.isAtEnd());
-    input.popLimit(limit);
-    assertEquals(5, input.readRawByte());
+    byte[] rawBytes = new byte[] {1, 2, 3, 4, 5};
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawBytes);
+      int limit = input.pushLimit(4);
+      // In order to expose the bug we need to read at least one byte to prime the
+      // buffer inside the CodedInputStream.
+      assertEquals(inputType.name(), 1, input.readRawByte());
+      // Skip to the end of the limit.
+      input.skipRawBytes(3);
+      assertTrue(inputType.name(), input.isAtEnd());
+      input.popLimit(limit);
+      assertEquals(inputType.name(), 5, input.readRawByte());
+    }
   }
 
   public void testReadHugeBlob() throws Exception {
@@ -399,19 +443,22 @@
     builder.setOptionalBytes(ByteString.copyFrom(blob));
     TestAllTypes message = builder.build();
 
-    // Serialize and parse it.  Make sure to parse from an InputStream, not
-    // directly from a ByteString, so that CodedInputStream uses buffered
-    // reading.
-    TestAllTypes message2 =
-      TestAllTypes.parseFrom(message.toByteString().newInput());
+    byte[] data = message.toByteArray();
+    for (InputType inputType : InputType.values()) {
+      // Serialize and parse it.  Make sure to parse from an InputStream, not
+      // directly from a ByteString, so that CodedInputStream uses buffered
+      // reading.
+      TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(data));
 
-    assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
+      assertEquals(inputType.name(), message.getOptionalBytes(), message2.getOptionalBytes());
 
-    // Make sure all the other fields were parsed correctly.
-    TestAllTypes message3 = TestAllTypes.newBuilder(message2)
-      .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
-      .build();
-    TestUtil.assertAllFieldsSet(message3);
+      // Make sure all the other fields were parsed correctly.
+      TestAllTypes message3 =
+          TestAllTypes.newBuilder(message2)
+              .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+              .build();
+      TestUtil.assertAllFieldsSet(message3);
+    }
   }
 
   public void testReadMaliciouslyLargeBlob() throws Exception {
@@ -421,17 +468,95 @@
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(0x7FFFFFFF);
-    output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
+    output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
+    byte[] data = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(data);
+      assertEquals(tag, input.readTag());
+      try {
+        input.readBytes();
+        fail(inputType.name() + ": Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
+    }
+  }
 
+  /**
+   * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT
+   * in size (2G or Integer#MAX_SIZE).
+   * @throws IOException
+   */
+  public void testParseMessagesCloseTo2G() throws IOException {
+    byte[] serializedMessage = getBigSerializedMessage();
+    // How many of these big messages do we need to take us near our 2G limit?
+    int count = Integer.MAX_VALUE / serializedMessage.length;
+    // Now make an inputstream that will fake a near 2G message of messages
+    // returning our big serialized message 'count' times.
+    InputStream is = new RepeatingInputStream(serializedMessage, count);
+    // Parse should succeed!
+    TestAllTypes.parseFrom(is);
+  }
+
+  /**
+   * Test there is an exception if a message exceeds
+   * CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE).
+   * @throws IOException
+   */
+  public void testParseMessagesOver2G() throws IOException {
+    byte[] serializedMessage = getBigSerializedMessage();
+    // How many of these big messages do we need to take us near our 2G limit?
+    int count = Integer.MAX_VALUE / serializedMessage.length;
+    // Now add one to take us over the limit
+    count++;
+    // Now make an inputstream that will fake a near 2G message of messages
+    // returning our big serialized message 'count' times.
+    InputStream is = new RepeatingInputStream(serializedMessage, count);
     try {
-      input.readBytes();
+      TestAllTypes.parseFrom(is);
       fail("Should have thrown an exception!");
     } catch (InvalidProtocolBufferException e) {
-      // success.
+      assertTrue(e.getMessage().contains("too large"));
+    }
+  }
+
+  /*
+   * @return A serialized big message.
+   */
+  private static byte[] getBigSerializedMessage() {
+    byte[] value = new byte[16 * 1024 * 1024]; 
+    ByteString bsValue = ByteString.wrap(value);
+    return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArray();
+  }
+
+  /*
+   * An input stream that repeats a byte arrays' content a number of times.
+   * Simulates really large input without consuming loads of memory. Used above
+   * to test the parsing behavior when the input size exceeds 2G or close to it.
+   */
+  private static class RepeatingInputStream extends InputStream {
+    private final byte[] serializedMessage;
+    private final int count;
+    private int index = 0;
+    private int offset = 0;
+
+    RepeatingInputStream(byte[] serializedMessage, int count) {
+      this.serializedMessage = serializedMessage;
+      this.count = count;
+    }
+
+    @Override
+    public int read() throws IOException {
+      if (this.offset == this.serializedMessage.length) {
+        this.index++;
+        this.offset = 0;
+      }
+      if (this.index == this.count) {
+        return -1;
+      }
+      return this.serializedMessage[offset++];
     }
   }
 
@@ -439,54 +564,55 @@
     if (depth == 0) {
       return TestRecursiveMessage.newBuilder().setI(5).build();
     } else {
-      return TestRecursiveMessage.newBuilder()
-        .setA(makeRecursiveMessage(depth - 1)).build();
+      return TestRecursiveMessage.newBuilder().setA(makeRecursiveMessage(depth - 1)).build();
     }
   }
 
-  private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+  private void assertMessageDepth(String msg, TestRecursiveMessage message, int depth) {
     if (depth == 0) {
-      assertFalse(message.hasA());
-      assertEquals(5, message.getI());
+      assertFalse(msg, message.hasA());
+      assertEquals(msg, 5, message.getI());
     } else {
-      assertTrue(message.hasA());
-      assertMessageDepth(message.getA(), depth - 1);
+      assertTrue(msg, message.hasA());
+      assertMessageDepth(msg, message.getA(), depth - 1);
     }
   }
 
   public void testMaliciousRecursion() throws Exception {
-    ByteString data100 = makeRecursiveMessage(100).toByteString();
-    ByteString data101 = makeRecursiveMessage(101).toByteString();
+    byte[] data100 = makeRecursiveMessage(100).toByteArray();
+    byte[] data101 = makeRecursiveMessage(101).toByteArray();
 
-    assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100);
+    for (InputType inputType : InputType.values()) {
+      assertMessageDepth(
+          inputType.name(), TestRecursiveMessage.parseFrom(inputType.newDecoder(data100)), 100);
 
-    try {
-      TestRecursiveMessage.parseFrom(data101);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
-    }
+      try {
+        TestRecursiveMessage.parseFrom(inputType.newDecoder(data101));
+        fail("Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
 
-    CodedInputStream input = data100.newCodedInput();
-    input.setRecursionLimit(8);
-    try {
-      TestRecursiveMessage.parseFrom(input);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
+      CodedInputStream input = inputType.newDecoder(data100);
+      input.setRecursionLimit(8);
+      try {
+        TestRecursiveMessage.parseFrom(input);
+        fail(inputType.name() + ": Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException e) {
+        // success.
+      }
     }
   }
 
   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
-      assertEquals(
-          InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
-          e.getMessage());
+    assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), e.getMessage());
   }
 
   public void testSizeLimit() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(
-            TestUtil.getAllSet().toByteString().newInput(), 16));
+    // NOTE: Size limit only applies to the stream-backed CIS.
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new SmallBlockInputStream(TestUtil.getAllSet().toByteArray(), 16));
     input.setSizeLimit(16);
 
     try {
@@ -498,8 +624,9 @@
   }
 
   public void testResetSizeCounter() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(new byte[256], 8));
+    // NOTE: Size limit only applies to the stream-backed CIS.
+    CodedInputStream input =
+        CodedInputStream.newInstance(new SmallBlockInputStream(new byte[256], 8));
     input.setSizeLimit(16);
     input.readRawBytes(16);
     assertEquals(16, input.getTotalBytesRead());
@@ -513,7 +640,7 @@
 
     input.resetSizeCounter();
     assertEquals(0, input.getTotalBytesRead());
-    input.readRawByte();  // No exception thrown.
+    input.readRawByte(); // No exception thrown.
     input.resetSizeCounter();
     assertEquals(0, input.getTotalBytesRead());
     input.readRawBytes(16);
@@ -521,20 +648,96 @@
     input.resetSizeCounter();
 
     try {
-      input.readRawBytes(17);  // Hits limit again.
+      input.readRawBytes(17); // Hits limit again.
       fail("Should have thrown an exception!");
     } catch (InvalidProtocolBufferException expected) {
       checkSizeLimitExceeded(expected);
     }
   }
+  
+  public void testRefillBufferWithCorrectSize() throws Exception {
+    // NOTE: refillBuffer only applies to the stream-backed CIS.
+    byte[] bytes = "123456789".getBytes("UTF-8");
+    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.writeRawByte(4);
+    output.flush();
+
+    // Input is two string with length 9 and one raw byte.
+    byte[] rawInput = rawOutput.toByteArray(); 
+    for (int inputStreamBufferLength = 8; 
+        inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) {
+      CodedInputStream input = CodedInputStream.newInstance(
+              new ByteArrayInputStream(rawInput), inputStreamBufferLength);
+      input.setSizeLimit(rawInput.length - 1);
+      input.readString();
+      input.readString(); 
+      try {
+        input.readRawByte(); // Hits limit.
+        fail("Should have thrown an exception!");
+      } catch (InvalidProtocolBufferException expected) {
+        checkSizeLimitExceeded(expected);
+      }
+    }
+  }
+
+  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());
+        input.readRawByte();
+      }
+      assertEquals(true, input.isAtEnd());
+    } catch (Exception e) {
+      fail("Catch exception in the testIsAtEnd");
+    }
+  }
+
+  public void testCurrentLimitExceeded() throws Exception {
+    byte[] bytes = "123456789".getBytes("UTF-8");
+    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+
+    byte[] rawInput = rawOutput.toByteArray();
+    CodedInputStream input = CodedInputStream.newInstance(
+              new ByteArrayInputStream(rawInput));
+    // The length of the whole rawInput
+    input.setSizeLimit(11);
+    // Some number that is smaller than the rawInput's length
+    // but larger than 2 
+    input.pushLimit(5);
+    try {
+      input.readString();
+      fail("Should have thrown an exception");
+    } catch (InvalidProtocolBufferException expected) {
+      assertEquals(expected.getMessage(), 
+          InvalidProtocolBufferException.truncatedMessage().getMessage());
+    }
+  }
 
   public void testSizeLimitMultipleMessages() throws Exception {
+    // NOTE: Size limit only applies to the stream-backed CIS.
     byte[] bytes = new byte[256];
     for (int i = 0; i < bytes.length; i++) {
       bytes[i] = (byte) i;
     }
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(bytes, 7));
+    CodedInputStream input = CodedInputStream.newInstance(new SmallBlockInputStream(bytes, 7));
     input.setSizeLimit(16);
     for (int i = 0; i < 256 / 16; i++) {
       byte[] message = input.readRawBytes(16);
@@ -547,10 +750,61 @@
     }
   }
 
+  public void testReadString() throws Exception {
+    String lorem = "Lorem ipsum dolor sit amet ";
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < 4096; i += lorem.length()) {
+      builder.append(lorem);
+    }
+    lorem = builder.toString().substring(0, 4096);
+    byte[] bytes = lorem.getBytes("UTF-8");
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readString();
+      assertEquals(inputType.name(), lorem, text);
+    }
+  }
+
+  public void testReadStringRequireUtf8() throws Exception {
+    String lorem = "Lorem ipsum dolor sit amet ";
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < 4096; i += lorem.length()) {
+      builder.append(lorem);
+    }
+    lorem = builder.toString().substring(0, 4096);
+    byte[] bytes = lorem.getBytes("UTF-8");
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readStringRequireUtf8();
+      assertEquals(inputType.name(), lorem, text);
+    }
+  }
+
   /**
-   * Tests that if we readString invalid UTF-8 bytes, no exception
-   * is thrown.  Instead, the invalid bytes are replaced with the Unicode
-   * "replacement character" U+FFFD.
+   * Tests that if we readString invalid UTF-8 bytes, no exception is thrown. Instead, the invalid
+   * bytes are replaced with the Unicode "replacement character" U+FFFD.
    */
   public void testReadStringInvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
@@ -559,18 +813,21 @@
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    String text = input.readString();
-    assertEquals(0xfffd, text.charAt(0));
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(inputType.name(), tag, input.readTag());
+      String text = input.readString();
+      assertEquals(inputType.name(), 0xfffd, text.charAt(0));
+    }
   }
 
   /**
-   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
-   * InvalidProtocolBufferException is thrown.
+   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProtocolBufferException
+   * is thrown.
    */
   public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
     ByteString.Output rawOutput = ByteString.newOutput();
@@ -579,16 +836,20 @@
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
     output.writeRawVarint32(tag);
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    try {
-      input.readStringRequireUtf8();
-      fail("Expected invalid UTF-8 exception.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream input = inputType.newDecoder(rawInput);
+      assertEquals(tag, input.readTag());
+      try {
+        input.readStringRequireUtf8();
+        fail(inputType.name() + ": Expected invalid UTF-8 exception.");
+      } catch (InvalidProtocolBufferException exception) {
+        assertEquals(
+            inputType.name(), "Protocol message had invalid UTF-8.", exception.getMessage());
+      }
     }
   }
 
@@ -608,13 +869,17 @@
   public void testInvalidTag() throws Exception {
     // Any tag number which corresponds to field number zero is invalid and
     // should throw InvalidProtocolBufferException.
-    for (int i = 0; i < 8; i++) {
-      try {
-        CodedInputStream.newInstance(bytes(i)).readTag();
-        fail("Should have thrown an exception.");
-      } catch (InvalidProtocolBufferException e) {
-        assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
-                     e.getMessage());
+    for (InputType inputType : InputType.values()) {
+      for (int i = 0; i < 8; i++) {
+        try {
+          inputType.newDecoder(bytes(i)).readTag();
+          fail(inputType.name() + ": Should have thrown an exception.");
+        } catch (InvalidProtocolBufferException e) {
+          assertEquals(
+              inputType.name(),
+              InvalidProtocolBufferException.invalidTag().getMessage(),
+              e.getMessage());
+        }
       }
     }
   }
@@ -626,10 +891,10 @@
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 23 });
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 45 });
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -639,20 +904,70 @@
     output.writeRawBytes(bytes);
 
     output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
 
-    byte[] result = inputStream.readByteArray();
-    assertEquals(0, result.length);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 23, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 45, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(bytesLength, result.length);
-    assertEquals((byte) 67, result[0]);
-    assertEquals((byte) 89, result[bytesLength - 1]);
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(rawInput);
+
+      byte[] result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 0, result.length);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 1, result.length);
+      assertEquals(inputType.name(), (byte) 23, result[0]);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), 1, result.length);
+      assertEquals(inputType.name(), (byte) 45, result[0]);
+      result = inputStream.readByteArray();
+      assertEquals(inputType.name(), bytesLength, result.length);
+      assertEquals(inputType.name(), (byte) 67, result[0]);
+      assertEquals(inputType.name(), (byte) 89, result[bytesLength - 1]);
+    }
+  }
+
+  public void testReadLargeByteStringFromInputStream() throws Exception {
+    byte[] bytes = new byte[1024 * 1024];
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] = (byte) (i & 0xFF);
+    }
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+    byte[] data = rawOutput.toByteString().toByteArray();
+
+    CodedInputStream input = CodedInputStream.newInstance(
+        new ByteArrayInputStream(data) {
+          @Override
+          public synchronized int available() {
+            return 0;
+          }
+        });
+    ByteString result = input.readBytes();
+    assertEquals(ByteString.copyFrom(bytes), result);
+  }
+
+  public void testReadLargeByteArrayFromInputStream() throws Exception {
+    byte[] bytes = new byte[1024 * 1024];
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] = (byte) (i & 0xFF);
+    }
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+    byte[] data = rawOutput.toByteString().toByteArray();
+
+    CodedInputStream input = CodedInputStream.newInstance(
+        new ByteArrayInputStream(data) {
+          @Override
+          public synchronized int available() {
+            return 0;
+          }
+        });
+    byte[] result = input.readByteArray();
+    assertTrue(Arrays.equals(bytes, result));
   }
 
   public void testReadByteBuffer() throws Exception {
@@ -662,10 +977,10 @@
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -675,21 +990,25 @@
     output.writeRawBytes(bytes);
 
     output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
 
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
+    byte[] rawInput = rawOutput.toByteString().toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(rawInput);
+
+      ByteBuffer result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+    }
   }
 
   public void testReadByteBufferAliasing() throws Exception {
@@ -699,10 +1018,10 @@
     output.writeRawVarint32(0);
     // One one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
+    output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
     output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
+    output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
@@ -711,59 +1030,107 @@
     output.writeRawVarint32(bytesLength);
     output.writeRawBytes(bytes);
     output.flush();
+
     byte[] data = byteArrayStream.toByteArray();
 
-    // Without aliasing
-    CodedInputStream inputStream = CodedInputStream.newInstance(data);
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
+    for (InputType inputType : InputType.values()) {
+      if (inputType == InputType.STREAM 
+          || inputType == InputType.STREAM_ITER_DIRECT 
+          || inputType == InputType.ITER_DIRECT) {
+        // Aliasing doesn't apply to stream-backed CIS.
+        continue;
+      }
 
-    // Enable aliasing
-    inputStream = CodedInputStream.newInstance(data);
-    inputStream.enableAliasing(true);
-    result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
+      // Without aliasing
+      CodedInputStream inputStream = inputType.newDecoder(data);
+      ByteBuffer result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      assertTrue(inputType.name(), result.array() != data);
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+
+      // Enable aliasing
+      inputStream = inputType.newDecoder(data, data.length);
+      inputStream.enableAliasing(true);
+      result = inputStream.readByteBuffer();
+      assertEquals(inputType.name(), 0, result.capacity());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 23, result.get());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), 1, result.capacity());
+      assertEquals(inputType.name(), (byte) 45, result.get());
+      result = inputStream.readByteBuffer();
+      if (result.hasArray()) {
+        assertTrue(inputType.name(), result.array() == data);
+      }
+      assertEquals(inputType.name(), bytesLength, result.capacity());
+      assertEquals(inputType.name(), (byte) 67, result.get());
+      result.position(bytesLength - 1);
+      assertEquals(inputType.name(), (byte) 89, result.get());
+    }
   }
 
   public void testCompatibleTypes() throws Exception {
     long data = 0x100000000L;
     Int64Message message = Int64Message.newBuilder().setData(data).build();
-    ByteString serialized = message.toByteString();
+    byte[] serialized = message.toByteArray();
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream inputStream = inputType.newDecoder(serialized);
 
-    // Test int64(long) is compatible with bool(boolean)
-    BoolMessage msg2 = BoolMessage.parseFrom(serialized);
-    assertTrue(msg2.getData());
+      // Test int64(long) is compatible with bool(boolean)
+      BoolMessage msg2 = BoolMessage.parseFrom(inputStream);
+      assertTrue(msg2.getData());
 
-    // Test int64(long) is compatible with int32(int)
-    Int32Message msg3 = Int32Message.parseFrom(serialized);
-    assertEquals((int) data, msg3.getData());
+      // Test int64(long) is compatible with int32(int)
+      inputStream = inputType.newDecoder(serialized);
+      Int32Message msg3 = Int32Message.parseFrom(inputStream);
+      assertEquals((int) data, msg3.getData());
+    }
+  }
+
+  public void testSkipInvalidVarint_FastPath() throws Exception {
+    // Fast path: We have >= 10 bytes available. Ensure we properly recognize a non-ending varint.
+    byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0};
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        // Expected
+      }
+    }
+  }
+
+  public void testSkipInvalidVarint_SlowPath() throws Exception {
+    // Slow path: < 10 bytes available. Ensure we properly recognize a non-ending varint.
+    byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1};
+    for (InputType inputType : InputType.values()) {
+      try {
+        CodedInputStream input = inputType.newDecoder(data);
+        input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
+        fail(inputType.name() + ": Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        // Expected
+      }
+    }
   }
 }
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 6018ea5..78f415c 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -30,19 +30,18 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
 import protobuf_unittest.UnittestProto.SparseEnumMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestSparseEnum;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link CodedOutputStream}.
@@ -50,118 +49,191 @@
  * @author kenton@google.com Kenton Varda
  */
 public class CodedOutputStreamTest extends TestCase {
-  /**
-   * Helper to construct a byte array from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
-   */
-  private byte[] bytes(int... bytesAsInts) {
-    byte[] bytes = new byte[bytesAsInts.length];
-    for (int i = 0; i < bytesAsInts.length; i++) {
-      bytes[i] = (byte) bytesAsInts[i];
-    }
-    return bytes;
+  private interface Coder {
+    CodedOutputStream stream();
+
+    byte[] toByteArray();
+
+    OutputType getOutputType();
   }
 
-  /** Arrays.asList() does not work with arrays of primitives.  :( */
-  private List<Byte> toList(byte[] bytes) {
-    List<Byte> result = new ArrayList<Byte>();
-    for (byte b : bytes) {
-      result.add(b);
+  private static final class OutputStreamCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final ByteArrayOutputStream output;
+
+    OutputStreamCoder(int size) {
+      output = new ByteArrayOutputStream();
+      stream = CodedOutputStream.newInstance(output, size);
     }
-    return result;
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      return output.toByteArray();
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.STREAM;
+    }
   }
 
-  private void assertEqualBytes(byte[] a, byte[] b) {
-    assertEquals(toList(a), toList(b));
+  private static final class ArrayCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final byte[] bytes;
+
+    ArrayCoder(int size) {
+      bytes = new byte[size];
+      stream = CodedOutputStream.newInstance(bytes);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      return Arrays.copyOf(bytes, stream.getTotalBytesWritten());
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.ARRAY;
+    }
   }
 
-  /**
-   * Writes the given value using writeRawVarint32() and writeRawVarint64() and
-   * checks that the result matches the given bytes.
-   */
-  private void assertWriteVarint(byte[] data, long value) throws Exception {
-    // Only test 32-bit write if the value fits into an int.
-    if (value == (int) value) {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint32((int) value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
+  private static final class NioHeapCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final ByteBuffer buffer;
+    private final int initialPosition;
 
-      // Also try computing size.
-      assertEquals(data.length,
-                   CodedOutputStream.computeRawVarint32Size((int) value));
+    NioHeapCoder(int size) {
+      this(size, 0);
     }
 
-    {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint64(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-
-      // Also try computing size.
-      assertEquals(data.length,
-                   CodedOutputStream.computeRawVarint64Size(value));
+    NioHeapCoder(int size, int initialPosition) {
+      this.initialPosition = initialPosition;
+      buffer = ByteBuffer.allocate(size);
+      buffer.position(initialPosition);
+      stream = CodedOutputStream.newInstance(buffer);
     }
 
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      // Only test 32-bit write if the value fits into an int.
-      if (value == (int) value) {
-        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-        CodedOutputStream output =
-          CodedOutputStream.newInstance(rawOutput, blockSize);
-        output.writeRawVarint32((int) value);
-        output.flush();
-        assertEqualBytes(data, rawOutput.toByteArray());
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      ByteBuffer dup = buffer.duplicate();
+      dup.position(initialPosition);
+      dup.limit(buffer.position());
+
+      byte[] bytes = new byte[dup.remaining()];
+      dup.get(bytes);
+      return bytes;
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.NIO_HEAP;
+    }
+  }
+
+  private static final class NioDirectCoder implements Coder {
+    private final int initialPosition;
+    private final CodedOutputStream stream;
+    private final ByteBuffer buffer;
+    private final boolean unsafe;
+
+    NioDirectCoder(int size, boolean unsafe) {
+      this(size, 0, unsafe);
+    }
+
+    NioDirectCoder(int size, int initialPosition, boolean unsafe) {
+      this.unsafe = unsafe;
+      this.initialPosition = initialPosition;
+      buffer = ByteBuffer.allocateDirect(size);
+      buffer.position(initialPosition);
+      stream =
+          unsafe
+              ? CodedOutputStream.newUnsafeInstance(buffer)
+              : CodedOutputStream.newSafeInstance(buffer);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      ByteBuffer dup = buffer.duplicate();
+      dup.position(initialPosition);
+      dup.limit(buffer.position());
+
+      byte[] bytes = new byte[dup.remaining()];
+      dup.get(bytes);
+      return bytes;
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return unsafe ? OutputType.NIO_DIRECT_SAFE : OutputType.NIO_DIRECT_UNSAFE;
+    }
+  }
+
+  private enum OutputType {
+    ARRAY() {
+      @Override
+      Coder newCoder(int size) {
+        return new ArrayCoder(size);
       }
-
-      {
-        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-        CodedOutputStream output =
-          CodedOutputStream.newInstance(rawOutput, blockSize);
-        output.writeRawVarint64(value);
-        output.flush();
-        assertEqualBytes(data, rawOutput.toByteArray());
+    },
+    NIO_HEAP() {
+      @Override
+      Coder newCoder(int size) {
+        return new NioHeapCoder(size);
       }
-    }
-  }
+    },
+    NIO_DIRECT_SAFE() {
+      @Override
+      Coder newCoder(int size) {
+        return new NioDirectCoder(size, false);
+      }
+    },
+    NIO_DIRECT_UNSAFE() {
+      @Override
+      Coder newCoder(int size) {
+        return new NioDirectCoder(size, true);
+      }
+    },
+    STREAM() {
+      @Override
+      Coder newCoder(int size) {
+        return new OutputStreamCoder(size);
+      }
+    };
 
-  private void assertVarintRoundTrip(long value) throws Exception {
-    {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint64(value);
-      output.flush();
-      byte[] bytes = rawOutput.toByteArray();
-      assertEquals(bytes.length, CodedOutputStream.computeRawVarint64Size(value));
-      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
-      assertEquals(value, input.readRawVarint64());
-    }
-
-    if (value == (int) value) {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint32((int) value);
-      output.flush();
-      byte[] bytes = rawOutput.toByteArray();
-      assertEquals(bytes.length, CodedOutputStream.computeRawVarint32Size((int) value));
-      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
-      assertEquals(value, input.readRawVarint32());
-    }
+    abstract Coder newCoder(int size);
   }
 
   /** Checks that invariants are maintained for varint round trip input and output. */
   public void testVarintRoundTrips() throws Exception {
-    assertVarintRoundTrip(0L);
-    for (int bits = 0; bits < 64; bits++) {
-      long value = 1L << bits;
-      assertVarintRoundTrip(value);
-      assertVarintRoundTrip(value + 1);
-      assertVarintRoundTrip(value - 1);
-      assertVarintRoundTrip(-value);
+    for (OutputType outputType : OutputType.values()) {
+      assertVarintRoundTrip(outputType, 0L);
+      for (int bits = 0; bits < 64; bits++) {
+        long value = 1L << bits;
+        assertVarintRoundTrip(outputType, value);
+        assertVarintRoundTrip(outputType, value + 1);
+        assertVarintRoundTrip(outputType, value - 1);
+        assertVarintRoundTrip(outputType, -value);
+      }
     }
   }
 
@@ -173,70 +245,25 @@
     // 14882
     assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
     // 2961488830
-    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x0bL << 28));
+    assertWriteVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
 
     // 64-bit
     // 7256456126
-    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x1bL << 28));
+    assertWriteVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
     // 41256202580718336
     assertWriteVarint(
-      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
-      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
-      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+        bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+        (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35)
+        | (0x24L << 42) | (0x49L << 49));
     // 11964378330978735131
     assertWriteVarint(
-      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
-      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
-      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
-      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
-  }
-
-  /**
-   * Parses the given bytes using writeRawLittleEndian32() and checks
-   * that the result matches the given value.
-   */
-  private void assertWriteLittleEndian32(byte[] data, int value)
-                                         throws Exception {
-    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawLittleEndian32(value);
-    output.flush();
-    assertEqualBytes(data, rawOutput.toByteArray());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      rawOutput = new ByteArrayOutputStream();
-      output = CodedOutputStream.newInstance(rawOutput, blockSize);
-      output.writeRawLittleEndian32(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-    }
-  }
-
-  /**
-   * Parses the given bytes using writeRawLittleEndian64() and checks
-   * that the result matches the given value.
-   */
-  private void assertWriteLittleEndian64(byte[] data, long value)
-                                         throws Exception {
-    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawLittleEndian64(value);
-    output.flush();
-    assertEqualBytes(data, rawOutput.toByteArray());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      rawOutput = new ByteArrayOutputStream();
-      output = CodedOutputStream.newInstance(rawOutput, blockSize);
-      output.writeRawLittleEndian64(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-    }
+        bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+        (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35)
+        | (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
   }
 
   /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
@@ -245,141 +272,139 @@
     assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
 
     assertWriteLittleEndian64(
-      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
-      0x123456789abcdef0L);
+        bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
     assertWriteLittleEndian64(
-      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
-      0x9abcdef012345678L);
+        bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
   }
 
   /** Test encodeZigZag32() and encodeZigZag64(). */
   public void testEncodeZigZag() throws Exception {
-    assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
+    assertEquals(0, CodedOutputStream.encodeZigZag32(0));
     assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
-    assertEquals(2, 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));
 
-    assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
+    assertEquals(0, CodedOutputStream.encodeZigZag64(0));
     assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
-    assertEquals(2, 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));
+    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));
 
     // 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)));
+    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)));
 
-    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)));
+    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)));
 
-    assertEquals(856912304801416L,
-      CodedOutputStream.encodeZigZag64(
-        CodedInputStream.decodeZigZag64(
-          856912304801416L)));
-    assertEquals(-75123905439571256L,
-      CodedOutputStream.encodeZigZag64(
-        CodedInputStream.decodeZigZag64(
-          -75123905439571256L)));
+    assertEquals(
+        856912304801416L,
+        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L)));
+    assertEquals(
+        -75123905439571256L,
+        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L)));
   }
 
   /** Tests writing a whole message with every field type. */
   public void testWriteWholeMessage() throws Exception {
+    final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray();
     TestAllTypes message = TestUtil.getAllSet();
 
-    byte[] rawBytes = message.toByteArray();
-    assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(message.getSerializedSize());
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      byte[] rawBytes = coder.toByteArray();
+      assertEqualBytes(outputType, expectedBytes, rawBytes);
+    }
 
     // Try different block sizes.
     for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output =
-        CodedOutputStream.newInstance(rawOutput, blockSize);
-      message.writeTo(output);
-      output.flush();
-      assertEqualBytes(rawBytes, rawOutput.toByteArray());
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, expectedBytes, coder.toByteArray());
     }
   }
 
-  /** Tests writing a whole message with every packed field type. Ensures the
-   * wire format of packed fields is compatible with C++. */
+  /**
+   * Tests writing a whole message with every packed field type. Ensures the
+   * wire format of packed fields is compatible with C++.
+   */
   public void testWriteWholePackedFieldsMessage() throws Exception {
+    byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
     TestPackedTypes message = TestUtil.getPackedSet();
 
-    byte[] rawBytes = message.toByteArray();
-    assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
-                     rawBytes);
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(message.getSerializedSize());
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      byte[] rawBytes = coder.toByteArray();
+      assertEqualBytes(outputType, expectedBytes, rawBytes);
+    }
   }
 
-  /** Test writing a message containing a negative enum value. This used to
+  /**
+   * 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.
    */
   public void testWriteMessageWithNegativeEnumValue() throws Exception {
-    SparseEnumMessage message = SparseEnumMessage.newBuilder()
-        .setSparseEnum(TestSparseEnum.SPARSE_E) .build();
+    SparseEnumMessage message =
+        SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build();
     assertTrue(message.getSparseEnum().getNumber() < 0);
-    byte[] rawBytes = message.toByteArray();
-    SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
-    assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+    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());
+    }
   }
 
   /** Test getTotalBytesWritten() */
   public void testGetTotalBytesWritten() throws Exception {
-    final int BUFFER_SIZE = 4 * 1024;
-    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE);
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+    Coder coder = OutputType.STREAM.newCoder(4 * 1024);
+
+    // Write some some bytes (more than the buffer can hold) and verify that totalWritten
+    // is correct.
     byte[] value = "abcde".getBytes(Internal.UTF_8);
     for (int i = 0; i < 1024; ++i) {
-      codedStream.writeRawBytes(value, 0, value.length);
+      coder.stream().writeRawBytes(value, 0, value.length);
     }
+    assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten());
+
+    // Now write an encoded string.
     String string =
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
     // Ensure we take the slower fast path.
-    assertTrue(CodedOutputStream.computeRawVarint32Size(string.length())
-        != CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
-    
-    codedStream.writeStringNoTag(string);
+    assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length())
+        != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+
+    coder.stream().writeStringNoTag(string);
+    coder.stream().flush();
     int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
-    
-    // Make sure we have written more bytes than the buffer could hold. This is
-    // to make the test complete.
-    assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
-    
+
     // Verify that the total bytes written is correct
-    assertEquals((value.length * 1024) + stringSize, codedStream.getTotalBytesWritten());
+    assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalBytesWritten());
   }
-  
+
   // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just
   //    this case.
   public void testWriteStringNoTag_fastpath() throws Exception {
@@ -390,14 +415,16 @@
       string += threeBytesPer;
     }
     // These checks ensure we will tickle the slower fast path.
-    assertEquals(1, CodedOutputStream.computeRawVarint32Size(string.length()));
+    assertEquals(1, CodedOutputStream.computeUInt32SizeNoTag(string.length()));
     assertEquals(
-        2, CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+        2, CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
     assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR);
-    
-    CodedOutputStream output =
-        CodedOutputStream.newInstance(ByteBuffer.allocate(bufferSize), bufferSize);
-    output.writeStringNoTag(string);
+
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(bufferSize + 2);
+      coder.stream().writeStringNoTag(string);
+      coder.stream().flush();
+    }
   }
 
   public void testWriteToByteBuffer() throws Exception {
@@ -461,86 +488,308 @@
 
   public void testWriteByteArrayWithOffsets() throws Exception {
     byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
-    byte[] destination = new byte[4];
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
-    codedStream.writeByteArrayNoTag(fullArray, 2, 2);
-    assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
-    assertEquals(3, codedStream.getTotalBytesWritten());
+    for (OutputType type : new OutputType[] {OutputType.ARRAY}) {
+      Coder coder = type.newCoder(4);
+      coder.stream().writeByteArrayNoTag(fullArray, 2, 2);
+      assertEqualBytes(type, bytes(0x02, 0x33, 0x44), coder.toByteArray());
+      assertEquals(3, coder.stream().getTotalBytesWritten());
+    }
   }
-  
+
+  public void testSerializeUtf8_MultipleSmallWrites() throws Exception {
+    final String source = "abcdefghijklmnopqrstuvwxyz";
+
+    // Generate the expected output if the source string is written 2 bytes at a time.
+    ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream();
+    for (int pos = 0; pos < source.length(); pos += 2) {
+      String substr = source.substring(pos, pos + 2);
+      expectedBytesStream.write(2);
+      expectedBytesStream.write(substr.getBytes(Internal.UTF_8));
+    }
+    final byte[] expectedBytes = expectedBytesStream.toByteArray();
+
+    // For each output type, write the source string 2 bytes at a time and verify the output.
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(expectedBytes.length);
+      for (int pos = 0; pos < source.length(); pos += 2) {
+        String substr = source.substring(pos, pos + 2);
+        coder.stream().writeStringNoTag(substr);
+      }
+      coder.stream().flush();
+      assertEqualBytes(outputType, expectedBytes, coder.toByteArray());
+    }
+  }
+
   public void testSerializeInvalidUtf8() throws Exception {
-    String[] invalidStrings = new String[] {
-        newString(Character.MIN_HIGH_SURROGATE),
-        "foobar" + newString(Character.MIN_HIGH_SURROGATE),
-        newString(Character.MIN_LOW_SURROGATE),
+    String[] invalidStrings = new String[] {newString(Character.MIN_HIGH_SURROGATE),
+        "foobar" + newString(Character.MIN_HIGH_SURROGATE), newString(Character.MIN_LOW_SURROGATE),
         "foobar" + newString(Character.MIN_LOW_SURROGATE),
-        newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)
-    };
-    
+        newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)};
+
     CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream());
     CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]);
+    CodedOutputStream outputWithByteBuffer =
+        CodedOutputStream.newInstance(ByteBuffer.allocate(10000));
     for (String s : invalidStrings) {
       // TODO(dweis): These should all fail; instead they are corrupting data.
       CodedOutputStream.computeStringSizeNoTag(s);
       outputWithStream.writeStringNoTag(s);
       outputWithArray.writeStringNoTag(s);
+      outputWithByteBuffer.writeStringNoTag(s);
     }
   }
-  
-  private static String newString(char... chars) {
-    return new String(chars);
+
+  // TODO(nathanmittler): This test can be deleted once we properly throw IOException while
+  // encoding invalid UTF-8 strings.
+  public void testSerializeInvalidUtf8FollowedByOutOfSpace() throws Exception {
+    final int notEnoughBytes = 4;
+    CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[notEnoughBytes]);
+    CodedOutputStream outputWithByteBuffer =
+        CodedOutputStream.newInstance(ByteBuffer.allocate(notEnoughBytes));
+
+    String invalidString = newString(Character.MIN_HIGH_SURROGATE, 'f', 'o', 'o', 'b', 'a', 'r');
+    try {
+      outputWithArray.writeStringNoTag(invalidString);
+      fail("Expected OutOfSpaceException");
+    } catch (OutOfSpaceException e) {
+      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+    }
+    try {
+      outputWithByteBuffer.writeStringNoTag(invalidString);
+      fail("Expected OutOfSpaceException");
+    } catch (OutOfSpaceException e) {
+      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+    }
   }
 
   /** Regression test for https://github.com/google/protobuf/issues/292 */
   public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
     String testCase = "Foooooooo";
-    assertEquals(CodedOutputStream.computeRawVarint32Size(testCase.length()),
-        CodedOutputStream.computeRawVarint32Size(testCase.length() * 3));
+    assertEquals(
+        CodedOutputStream.computeUInt32SizeNoTag(testCase.length()),
+        CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3));
     assertEquals(11, CodedOutputStream.computeStringSize(1, testCase));
     // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
     // An array of size 1 will cause a failure when trying to write the varint.
-    for (int i = 0; i < 11; i++) {
-      CodedOutputStream output = CodedOutputStream.newInstance(new byte[i]);
-      try {
-        output.writeString(1, testCase);
-        fail("Should have thrown an out of space exception");
-      } catch (CodedOutputStream.OutOfSpaceException expected) {}
+    for (OutputType outputType :
+        new OutputType[] {
+          OutputType.ARRAY,
+          OutputType.NIO_HEAP,
+          OutputType.NIO_DIRECT_SAFE,
+          OutputType.NIO_DIRECT_UNSAFE
+        }) {
+      for (int i = 0; i < 11; i++) {
+        Coder coder = outputType.newCoder(i);
+        try {
+          coder.stream().writeString(1, testCase);
+          fail("Should have thrown an out of space exception");
+        } catch (CodedOutputStream.OutOfSpaceException expected) {
+        }
+      }
     }
   }
-  
+
   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
     // char, hence causing the length delimiter varint to sometimes require more
     // bytes for the Unicode strings than the ASCII string of the same length.
     int[] lengths = new int[] {
-            0,
-            1,
-            (1 << 4) - 1,  // 1 byte for ASCII and Unicode
-            (1 << 7) - 1,  // 1 byte for ASCII, 2 bytes for Unicode
-            (1 << 11) - 1, // 2 bytes for ASCII and Unicode
-            (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
-            (1 << 17) - 1, // 3 bytes for ASCII and Unicode
+        0,
+        1,
+        (1 << 4) - 1, // 1 byte for ASCII and Unicode
+        (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
+        (1 << 11) - 1, // 2 bytes for ASCII and Unicode
+        (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
+        (1 << 17) - 1,
+        // 3 bytes for ASCII and Unicode
     };
-    for (int i : lengths) {
-      testEncodingOfString('q', i);      // 1 byte per char
-      testEncodingOfString('\u07FF', i); // 2 bytes per char
-      testEncodingOfString('\u0981', i); // 3 bytes per char
+    for (OutputType outputType : OutputType.values()) {
+      for (int i : lengths) {
+        testEncodingOfString(outputType, 'q', i); // 1 byte per char
+        testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char
+        testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char
+      }
     }
   }
 
-  private void testEncodingOfString(char c, int length) throws Exception {
-    String fullString = fullString(c, length);
-    TestAllTypes testAllTypes = TestAllTypes.newBuilder()
-        .setOptionalString(fullString)
-        .build();
-    assertEquals(
-        fullString, TestAllTypes.parseFrom(testAllTypes.toByteArray()).getOptionalString());
+  public void testNioEncodersWithInitialOffsets() throws Exception {
+    String value = "abc";
+    for (Coder coder :
+        new Coder[] {
+          new NioHeapCoder(10, 2), new NioDirectCoder(10, 2, false), new NioDirectCoder(10, 2, true)
+        }) {
+      coder.stream().writeStringNoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(coder.getOutputType(), new byte[] {3, 'a', 'b', 'c'}, coder.toByteArray());
+    }
   }
 
-  private String fullString(char c, int length) {
+  /**
+   * Parses the given bytes using writeRawLittleEndian32() and checks
+   * that the result matches the given value.
+   */
+  private static void assertWriteLittleEndian32(byte[] data, int value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(data.length);
+      coder.stream().writeFixed32NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(outputType, data, coder.toByteArray());
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      coder.stream().writeFixed32NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+    }
+  }
+
+  /**
+   * Parses the given bytes using writeRawLittleEndian64() and checks
+   * that the result matches the given value.
+   */
+  private static void assertWriteLittleEndian64(byte[] data, long value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(data.length);
+      coder.stream().writeFixed64NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(outputType, data, coder.toByteArray());
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      coder.stream().writeFixed64NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+    }
+  }
+
+  private static String newString(char... chars) {
+    return new String(chars);
+  }
+
+  private static void testEncodingOfString(OutputType outputType, char c, int length)
+      throws Exception {
+    String fullString = fullString(c, length);
+    TestAllTypes testAllTypes = TestAllTypes.newBuilder().setOptionalString(fullString).build();
+    Coder coder = outputType.newCoder(testAllTypes.getSerializedSize());
+    testAllTypes.writeTo(coder.stream());
+    coder.stream().flush();
+    assertEquals(
+        "OuputType: " + outputType,
+        fullString,
+        TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString());
+  }
+
+  private static String fullString(char c, int length) {
     char[] result = new char[length];
     Arrays.fill(result, c);
     return new String(result);
   }
+
+  /**
+   * Helper to construct a byte array from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private static byte[] bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return bytes;
+  }
+
+  /** Arrays.asList() does not work with arrays of primitives.  :( */
+  private static List<Byte> toList(byte[] bytes) {
+    List<Byte> result = new ArrayList<Byte>();
+    for (byte b : bytes) {
+      result.add(b);
+    }
+    return result;
+  }
+
+  private static void assertEqualBytes(OutputType outputType, byte[] a, byte[] b) {
+    assertEquals(outputType.name(), toList(a), toList(b));
+  }
+
+  /**
+   * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+   * checks that the result matches the given bytes.
+   */
+  private static void assertWriteVarint(byte[] data, long value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      // Only test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
+        Coder coder = outputType.newCoder(10);
+        coder.stream().writeUInt32NoTag((int) value);
+        coder.stream().flush();
+        assertEqualBytes(outputType, data, coder.toByteArray());
+
+        // Also try computing size.
+        assertEquals(data.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+      }
+
+      {
+        Coder coder = outputType.newCoder(10);
+        coder.stream().writeUInt64NoTag(value);
+        coder.stream().flush();
+        assertEqualBytes(outputType, data, coder.toByteArray());
+
+        // Also try computing size.
+        assertEquals(data.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+      }
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      // Only test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
+        Coder coder = OutputType.STREAM.newCoder(blockSize);
+        coder.stream().writeUInt64NoTag((int) value);
+        coder.stream().flush();
+        assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+
+        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+        CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, blockSize);
+        output.writeUInt32NoTag((int) value);
+        output.flush();
+        assertEqualBytes(OutputType.STREAM, data, rawOutput.toByteArray());
+      }
+
+      {
+        Coder coder = OutputType.STREAM.newCoder(blockSize);
+        coder.stream().writeUInt64NoTag(value);
+        coder.stream().flush();
+        assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+      }
+    }
+  }
+
+  private static void assertVarintRoundTrip(OutputType outputType, long value) throws Exception {
+    {
+      Coder coder = outputType.newCoder(10);
+      coder.stream().writeUInt64NoTag(value);
+      coder.stream().flush();
+      byte[] bytes = coder.toByteArray();
+      assertEquals(
+          outputType.name(), bytes.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(outputType.name(), value, input.readRawVarint64());
+    }
+
+    if (value == (int) value) {
+      Coder coder = outputType.newCoder(10);
+      coder.stream().writeUInt32NoTag((int) value);
+      coder.stream().flush();
+      byte[] bytes = coder.toByteArray();
+      assertEquals(
+          outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(outputType.name(), value, input.readRawVarint32());
+    }
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java
new file mode 100644
index 0000000..359d4d7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java
@@ -0,0 +1,325 @@
+package com.google.protobuf;
+
+import com.google.protobuf.Utf8.Processor;
+import com.google.protobuf.Utf8.SafeProcessor;
+import com.google.protobuf.Utf8.UnsafeProcessor;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+import junit.framework.TestCase;
+
+public class DecodeUtf8Test extends TestCase {
+  private static Logger logger = Logger.getLogger(DecodeUtf8Test.class.getName());
+
+  private static final Processor SAFE_PROCESSOR = new SafeProcessor();
+  private static final Processor UNSAFE_PROCESSOR = new UnsafeProcessor();
+
+  public void testRoundTripAllValidChars() throws Exception {
+    for (int i = Character.MIN_CODE_POINT; i < Character.MAX_CODE_POINT; i++) {
+      if (i < Character.MIN_SURROGATE || i > Character.MAX_SURROGATE) {
+        String str = new String(Character.toChars(i));
+        assertRoundTrips(str);
+      }
+    }
+  }
+
+  // Test all 1, 2, 3 invalid byte combinations. Valid ones would have been covered above.
+
+  public void testOneByte() throws Exception {
+    int valid = 0;
+    for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+      ByteString bs = ByteString.copyFrom(new byte[] { (byte) i });
+      if (!bs.isValidUtf8()) {
+        assertInvalid(bs.toByteArray());
+      } else {
+        valid++;
+      }
+    }
+    assertEquals(IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+  }
+
+  public void testTwoBytes() throws Exception {
+    int valid = 0;
+    for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+      for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
+        ByteString bs = ByteString.copyFrom(new byte[]{(byte) i, (byte) j});
+        if (!bs.isValidUtf8()) {
+          assertInvalid(bs.toByteArray());
+        } else {
+          valid++;
+        }
+      }
+    }
+    assertEquals(IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+  }
+
+  public void testThreeBytes() throws Exception {
+    // Travis' OOM killer doesn't like this test
+    if (System.getenv("TRAVIS") == null) {
+      int count = 0;
+      int valid = 0;
+      for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+        for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
+          for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) {
+            byte[] bytes = new byte[]{(byte) i, (byte) j, (byte) k};
+            ByteString bs = ByteString.copyFrom(bytes);
+            if (!bs.isValidUtf8()) {
+              assertInvalid(bytes);
+            } else {
+              valid++;
+            }
+            count++;
+            if (count % 1000000L == 0) {
+              logger.info("Processed " + (count / 1000000L) + " million characters");
+            }
+          }
+        }
+      }
+      assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
+    }
+  }
+
+  /**
+   * Tests that round tripping of a sample of four byte permutations work.
+   */
+  public void testInvalid_4BytesSamples() throws Exception {
+    // Bad trailing bytes
+    assertInvalid(0xF0, 0xA4, 0xAD, 0x7F);
+    assertInvalid(0xF0, 0xA4, 0xAD, 0xC0);
+
+    // Special cases for byte2
+    assertInvalid(0xF0, 0x8F, 0xAD, 0xA2);
+    assertInvalid(0xF4, 0x90, 0xAD, 0xA2);
+  }
+
+  public void testRealStrings() throws Exception {
+    // English
+    assertRoundTrips("The quick brown fox jumps over the lazy dog");
+    // German
+    assertRoundTrips("Quizdeltagerne spiste jordb\u00e6r med fl\u00f8de, mens cirkusklovnen");
+    // Japanese
+    assertRoundTrips(
+        "\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092");
+    // Hebrew
+    assertRoundTrips(
+        "\u05d3\u05d2 \u05e1\u05e7\u05e8\u05df \u05e9\u05d8 \u05d1\u05d9\u05dd "
+            + "\u05de\u05d0\u05d5\u05db\u05d6\u05d1 \u05d5\u05dc\u05e4\u05ea\u05e2"
+            + " \u05de\u05e6\u05d0 \u05dc\u05d5 \u05d7\u05d1\u05e8\u05d4 "
+            + "\u05d0\u05d9\u05da \u05d4\u05e7\u05dc\u05d9\u05d8\u05d4");
+    // Thai
+    assertRoundTrips(
+        " \u0e08\u0e07\u0e1d\u0e48\u0e32\u0e1f\u0e31\u0e19\u0e1e\u0e31\u0e12"
+            + "\u0e19\u0e32\u0e27\u0e34\u0e0a\u0e32\u0e01\u0e32\u0e23");
+    // Chinese
+    assertRoundTrips(
+        "\u8fd4\u56de\u94fe\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4ee3\u7406\u9879\u9009\u62e9\u5668");
+    // Chinese with 4-byte chars
+    assertRoundTrips("\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78"
+        + "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F"
+        + "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2");
+    // Mixed
+    assertRoundTrips(
+        "The quick brown \u3044\u308d\u306f\u306b\u307b\u3078\u8fd4\u56de\u94fe"
+            + "\u4e2d\u7684\u4e0b\u4e00");
+  }
+
+  public void testOverlong() throws Exception {
+    assertInvalid(0xc0, 0xaf);
+    assertInvalid(0xe0, 0x80, 0xaf);
+    assertInvalid(0xf0, 0x80, 0x80, 0xaf);
+
+    // Max overlong
+    assertInvalid(0xc1, 0xbf);
+    assertInvalid(0xe0, 0x9f, 0xbf);
+    assertInvalid(0xf0 ,0x8f, 0xbf, 0xbf);
+
+    // null overlong
+    assertInvalid(0xc0, 0x80);
+    assertInvalid(0xe0, 0x80, 0x80);
+    assertInvalid(0xf0, 0x80, 0x80, 0x80);
+  }
+
+  public void testIllegalCodepoints() throws Exception {
+    // Single surrogate
+    assertInvalid(0xed, 0xa0, 0x80);
+    assertInvalid(0xed, 0xad, 0xbf);
+    assertInvalid(0xed, 0xae, 0x80);
+    assertInvalid(0xed, 0xaf, 0xbf);
+    assertInvalid(0xed, 0xb0, 0x80);
+    assertInvalid(0xed, 0xbe, 0x80);
+    assertInvalid(0xed, 0xbf, 0xbf);
+
+    // Paired surrogates
+    assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80);
+    assertInvalid(0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf);
+    assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80);
+    assertInvalid(0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf);
+    assertInvalid(0xed, 0xae, 0x80, 0xed, 0xb0, 0x80);
+    assertInvalid(0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf);
+    assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80);
+    assertInvalid(0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf);
+  }
+
+  public void testBufferSlice() throws Exception {
+    String str = "The quick brown fox jumps over the lazy dog";
+    assertRoundTrips(str, 10, 4);
+    assertRoundTrips(str, str.length(), 0);
+  }
+
+  public void testInvalidBufferSlice() throws Exception {
+    byte[] bytes  = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8);
+    assertInvalidSlice(bytes, bytes.length - 3, 4);
+    assertInvalidSlice(bytes, bytes.length, 1);
+    assertInvalidSlice(bytes, bytes.length + 1, 0);
+    assertInvalidSlice(bytes, 0, bytes.length + 1);
+  }
+
+  private void assertInvalid(int... bytesAsInt) throws Exception {
+    byte[] bytes = new byte[bytesAsInt.length];
+    for (int i = 0; i < bytesAsInt.length; i++) {
+      bytes[i] = (byte) bytesAsInt[i];
+    }
+    assertInvalid(bytes);
+  }
+
+  private void assertInvalid(byte[] bytes) throws Exception {
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+
+    ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+    direct.put(bytes);
+    direct.flip();
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+
+    ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+    heap.put(bytes);
+    heap.flip();
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  private void assertInvalidSlice(byte[] bytes, int index, int size) throws Exception {
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(bytes, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+
+    ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+    direct.put(bytes);
+    direct.flip();
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(direct, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(direct, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+
+    ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+    heap.put(bytes);
+    heap.flip();
+    try {
+      UNSAFE_PROCESSOR.decodeUtf8(heap, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+    try {
+      SAFE_PROCESSOR.decodeUtf8(heap, index, size);
+      fail();
+    } catch (ArrayIndexOutOfBoundsException e) {
+      // Expected.
+    }
+  }
+
+  private void assertRoundTrips(String str) throws Exception {
+    assertRoundTrips(str, 0, -1);
+  }
+
+  private void assertRoundTrips(String str, int index, int size) throws Exception {
+    byte[] bytes = str.getBytes(Internal.UTF_8);
+    if (size == -1) {
+      size = bytes.length;
+    }
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size));
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        SAFE_PROCESSOR.decodeUtf8(bytes, index, size));
+
+    ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
+    direct.put(bytes);
+    direct.flip();
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        UNSAFE_PROCESSOR.decodeUtf8(direct, index, size));
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        SAFE_PROCESSOR.decodeUtf8(direct, index, size));
+
+    ByteBuffer heap = ByteBuffer.allocate(bytes.length);
+    heap.put(bytes);
+    heap.flip();
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        UNSAFE_PROCESSOR.decodeUtf8(heap, index, size));
+    assertDecode(new String(bytes, index, size, Internal.UTF_8),
+        SAFE_PROCESSOR.decodeUtf8(heap, index, size));
+  }
+
+  private void assertDecode(String expected, String actual) {
+    if (!expected.equals(actual)) {
+      fail("Failure: Expected (" + codepoints(expected) + ") Actual (" + codepoints(actual) + ")");
+    }
+  }
+
+  private List<String> codepoints(String str) {
+    List<String> codepoints = new ArrayList<String>();
+    for (int i = 0; i < str.length(); i++) {
+      codepoints.add(Long.toHexString(str.charAt(i)));
+    }
+    return codepoints;
+  }
+
+}
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 e7905f7..9c0997c 100644
--- a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -31,29 +31,28 @@
 package com.google.protobuf;
 
 import protobuf_unittest.UnittestProto.TestDeprecatedFields;
-
-import junit.framework.TestCase;
-
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Method;
+import junit.framework.TestCase;
+
 /**
  * Test field deprecation
- * 
+ *
  * @author birdo@google.com (Roberto Scaramuzzi)
  */
 public class DeprecatedFieldTest extends TestCase {
   private String[] deprecatedGetterNames = {
       "hasDeprecatedInt32",
       "getDeprecatedInt32"};
-  
+
   private String[] deprecatedBuilderGetterNames = {
       "hasDeprecatedInt32",
       "getDeprecatedInt32",
       "clearDeprecatedInt32"};
-  
+
   private String[] deprecatedBuilderSetterNames = {
-      "setDeprecatedInt32"}; 
-  
+      "setDeprecatedInt32"};
+
   public void testDeprecatedField() throws Exception {
     Class<?> deprecatedFields = TestDeprecatedFields.class;
     Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
@@ -73,7 +72,15 @@
           isDeprecated(method));
     }
   }
-  
+
+  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));
+  }
+
   private boolean isDeprecated(AnnotatedElement annotated) {
     return annotated.isAnnotationPresent(Deprecated.class);
   }
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 82ff34a..b60cd62 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -55,16 +55,15 @@
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestJsonName;
 import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
 import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestReservedFields;
 import protobuf_unittest.UnittestProto.TestService;
-
-import junit.framework.TestCase;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link Descriptors}.
@@ -383,6 +382,14 @@
     assertEquals(Long.valueOf(8765432109L),
       field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
 
+    OneofDescriptor oneof = descriptor.getOneofs().get(0);
+    assertNotNull(oneof);
+
+    assertTrue(
+      oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
+    assertEquals(Integer.valueOf(-99),
+      oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
+
     EnumDescriptor enumType =
       UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
 
@@ -573,6 +580,42 @@
     }
   }
 
+  public void testUnknownFieldsDenied() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+
+    try {
+      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(e.getMessage().indexOf("Bar") != -1);
+      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+    }
+  }
+
+  public void testUnknownFieldsAllowed() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
+  }
+
   public void testHiddenDependency() throws Exception {
     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
         .setName("bar.proto")
@@ -762,4 +805,15 @@
     Descriptors.FileDescriptor.buildFrom(
         fileDescriptorProto, new FileDescriptor[0]);
   }
+
+  public void testFieldJsonName() throws Exception {
+    Descriptor d = TestJsonName.getDescriptor();
+    assertEquals(6, d.getFields().size());
+    assertEquals("fieldName1", d.getFields().get(0).getJsonName());
+    assertEquals("fieldName2", d.getFields().get(1).getJsonName());
+    assertEquals("FieldName3", d.getFields().get(2).getJsonName());
+    assertEquals("FieldName4", d.getFields().get(3).getJsonName());
+    assertEquals("FIELDNAME5", d.getFields().get(4).getJsonName());
+    assertEquals("@type", d.getFields().get(5).getJsonName());
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
new file mode 100644
index 0000000..0f09a51
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
@@ -0,0 +1,157 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static org.junit.Assert.assertEquals;
+
+import protobuf_unittest.UnittestProto;
+import proto3_unittest.UnittestProto3;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for discard or preserve unknown fields. */
+@RunWith(JUnit4.class)
+public class DiscardUnknownFieldsTest {
+  @Test
+  public void testProto2() throws Exception {
+    testProto2Message(
+          UnittestProto.TestEmptyMessage.getDefaultInstance());
+    testProto2Message(
+          UnittestProto.TestEmptyMessageWithExtensions.getDefaultInstance());
+    testProto2Message(
+          DynamicMessage.getDefaultInstance(UnittestProto.TestEmptyMessage.getDescriptor()));
+    testProto2Message(
+          DynamicMessage.getDefaultInstance(
+              UnittestProto.TestEmptyMessageWithExtensions.getDescriptor()));
+  }
+
+  @Test
+  public void testProto3() throws Exception {
+    testProto3Message(UnittestProto3.TestEmptyMessage.getDefaultInstance());
+    testProto3Message(
+        DynamicMessage.getDefaultInstance(UnittestProto3.TestEmptyMessage.getDescriptor()));
+  }
+
+  private static void testProto2Message(Message message) throws Exception {
+    assertUnknownFieldsDefaultPreserved(message);
+    assertUnknownFieldsExplicitlyDiscarded(message);
+    assertReuseCodedInputStreamPreserve(message);
+    assertUnknownFieldsInUnknownFieldSetArePreserve(message);
+  }
+
+  private static void testProto3Message(Message message) throws Exception {
+    CodedInputStream.setProto3KeepUnknownsByDefaultForTest();
+    assertUnknownFieldsDefaultPreserved(message);
+    assertUnknownFieldsExplicitlyDiscarded(message);
+    assertReuseCodedInputStreamPreserve(message);
+    assertUnknownFieldsInUnknownFieldSetArePreserve(message);
+    CodedInputStream.setProto3DiscardUnknownsByDefaultForTest();
+    assertUnknownFieldsDefaultDiscarded(message);
+    assertUnknownFieldsExplicitlyDiscarded(message);
+    assertUnknownFieldsInUnknownFieldSetAreDiscarded(message);
+  }
+
+  private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception {
+    final int messageSize = payload.size();
+    byte[] copied = new byte[messageSize * 2];
+    payload.copyTo(copied, 0);
+    payload.copyTo(copied, messageSize);
+    CodedInputStream input = CodedInputStream.newInstance(copied);
+    {
+      // 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());
+      input.popLimit(oldLimit);
+    }
+    {
+      // Use the normal parser to parse the remaining payload should have unknown fields preserved.
+      Message parsed = message.getParserForType().parseFrom(input);
+      assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    }
+  }
+
+  /**
+   * {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
+   * Message.Builder#mergeUnknownFields(UnknownFieldSet)} should preserve the unknown fields.
+   */
+  private static void assertUnknownFieldsInUnknownFieldSetArePreserve(Message message)
+      throws Exception {
+    UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
+    Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
+    assertEquals(message.getClass().getName(), payload, built.toByteString());
+
+  }
+  /**
+   * {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
+   * Message.Builder#mergeUnknownFields(UnknownFieldSet)} should discard the unknown fields.
+   */
+  private static void assertUnknownFieldsInUnknownFieldSetAreDiscarded(Message message)
+      throws Exception {
+    UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
+    Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
+    assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
+  }
+
+  private static void assertUnknownFieldsDefaultPreserved(MessageLite message) throws Exception {
+    {
+      MessageLite parsed = message.getParserForType().parseFrom(payload);
+      assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    }
+
+    {
+      MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
+      assertEquals(message.getClass().getName(), payload, parsed.toByteString());
+    }
+  }
+
+  private static void assertUnknownFieldsDefaultDiscarded(MessageLite message) throws Exception {
+    {
+      MessageLite parsed = message.getParserForType().parseFrom(payload);
+      assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+    }
+
+    {
+      MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
+      assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+    }
+  }
+
+  private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
+    Message parsed =
+        DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
+    assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
+  }
+
+  private static final ByteString payload =
+      TestUtilLite.getAllLiteSetBuilder().build().toByteString();
+}
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 d3deaa0..923d7f4 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -32,61 +32,48 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
+import com.google.protobuf.Internal.DoubleList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link DoubleArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class DoubleArrayListTest extends TestCase {
-  
-  private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
+
+  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 {
     list = new DoubleArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(DoubleArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addDouble(2);
+    list.addDouble(3);
     list.addDouble(4);
-    list.addDouble(6);
-    list.addDouble(8);
+    list.addDouble(5);
+    list.addDouble(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
-  public void testCopyConstructor() {
-    DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
 
-    copy = new DoubleArrayList(DoubleArrayList.emptyList());
-    assertEquals(DoubleArrayList.emptyList(), copy);
-    
-    copy = new DoubleArrayList(asList(1D, 2D, 3D));
-    assertEquals(asList(1D, 2D, 3D), copy);
-
-    copy = new DoubleArrayList(Collections.<Double>emptyList());
-    assertEquals(DoubleArrayList.emptyList(), copy);
-  }
-  
   public void testModificationWithIteration() {
     list.addAll(asList(1D, 2D, 3D, 4D));
     Iterator<Double> iterator = list.iterator();
@@ -95,7 +82,7 @@
     assertEquals(1D, (double) iterator.next());
     list.set(0, 1D);
     assertEquals(2D, (double) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -103,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0D);
     try {
@@ -113,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1D, (double) TERTIARY_LIST.get(0));
     assertEquals(2D, (double) TERTIARY_LIST.get(1));
     assertEquals(3D, (double) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -133,19 +120,19 @@
       // expected
     }
   }
-  
-  public void testGetInt() {
+
+  public void testGetDouble() {
     assertEquals(1D, TERTIARY_LIST.getDouble(0));
     assertEquals(2D, TERTIARY_LIST.getDouble(1));
     assertEquals(3D, TERTIARY_LIST.getDouble(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -153,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, DoubleArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addDouble(2);
+    list.addDouble(3);
     list.addDouble(4);
     list.addDouble(6);
     list.addDouble(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16D);
+
+    list.add(17D);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addDouble(2);
     list.addDouble(4);
-    
-    assertEquals(2D, (double) list.set(0, 0D));
-    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(2D, (double) list.set(0, 3D));
+    assertEquals(3D, list.getDouble(0));
 
     assertEquals(4D, (double) list.set(1, 0D));
     assertEquals(0D, list.getDouble(1));
-    
+
     try {
       list.set(-1, 0D);
       fail();
@@ -196,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetInt() {
-    list.addDouble(2);
-    list.addDouble(4);
-    
-    assertEquals(2D, list.setDouble(0, 0));
+
+  public void testSetDouble() {
+    list.addDouble(1);
+    list.addDouble(3);
+
+    assertEquals(1D, list.setDouble(0, 0));
     assertEquals(0D, list.getDouble(0));
 
-    assertEquals(4D, list.setDouble(1, 0));
+    assertEquals(3D, list.setDouble(1, 0));
     assertEquals(0D, list.getDouble(1));
-    
+
     try {
       list.setDouble(-1, 0);
       fail();
@@ -221,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -231,29 +218,31 @@
     assertTrue(list.add(3D));
     list.add(0, 4D);
     assertEquals(asList(4D, 2D, 3D), list);
-    
+
     list.add(0, 1D);
     list.add(0, 0D);
     // Force a resize by getting up to 11 elements.
     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);
-    
+    assertEquals(
+        asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D),
+        list);
+
     try {
       list.add(-1, 5D);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5D);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
-  public void testAddInt() {
+
+  public void testAddDouble() {
     assertEquals(0, list.size());
 
     list.addDouble(2);
@@ -262,7 +251,7 @@
     list.addDouble(3);
     assertEquals(asList(2D, 3D), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -270,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1D, (double) list.get(0));
     assertEquals(1D, list.getDouble(0));
-    
+
     assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list);
 
     assertFalse(list.addAll(Collections.<Double>emptyList()));
     assertFalse(list.addAll(DoubleArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1D, (double) list.remove(0));
@@ -294,96 +283,110 @@
 
     assertEquals(2D, (double) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
+  public void testRemoveEndOfCapacity() {
+    DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addDouble(3);
+    toRemove.remove(0);
+    assertEquals(0, toRemove.size());
+  }
+
+  public void testSublistRemoveEndOfCapacity() {
+    DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addDouble(3);
+    toRemove.subList(0, 1).clear();
+    assertEquals(0, toRemove.size());
+  }
+
   private void assertImmutable(DoubleArrayList list) {
     if (list.contains(1D)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new DoubleArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addDouble(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -397,28 +400,28 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
@@ -432,28 +435,28 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setDouble(0, 0);
       fail();
@@ -461,7 +464,7 @@
       // expected
     }
   }
-  
+
   private static DoubleArrayList newImmutableDoubleArrayList(double... elements) {
     DoubleArrayList list = new DoubleArrayList();
     for (double element : elements) {
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 55144e7..77d14f6 100644
--- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -33,14 +33,12 @@
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
-
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
-
-import junit.framework.TestCase;
 import java.util.Arrays;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link DynamicMessage}.  See also {@link MessageTest}, which
diff --git a/java/core/src/test/java/com/google/protobuf/EnumTest.java b/java/core/src/test/java/com/google/protobuf/EnumTest.java
new file mode 100644
index 0000000..14c7406
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/EnumTest.java
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+public class EnumTest extends TestCase {
+  
+  public void testForNumber() {
+    ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber());
+    assertEquals(ForeignEnum.FOREIGN_BAR, e);
+
+    e = ForeignEnum.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumber_oneof() {
+    TestAllTypes.OneofFieldCase e = TestAllTypes.OneofFieldCase.forNumber(
+        TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+    assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+    e = TestAllTypes.OneofFieldCase.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumberLite() {
+    ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e);
+
+    e = ForeignEnumLite.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumberLite_oneof() {
+    TestAllTypesLite.OneofFieldCase e = TestAllTypesLite.OneofFieldCase.forNumber(
+        TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+    assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+    e = TestAllTypesLite.OneofFieldCase.forNumber(1000);
+    assertEquals(null, e);
+  }
+}
+
diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
new file mode 100644
index 0000000..6157e58
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -0,0 +1,276 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.NonNestedExtension;
+import protobuf_unittest.NonNestedExtensionLite;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Tests for {@link ExtensionRegistryFactory} and the {@link ExtensionRegistry} instances it
+ * creates.
+ *
+ * <p>This test simulates the runtime behaviour of the ExtensionRegistryFactory by delegating test
+ * definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of
+ * which is executed using a custom ClassLoader, simulating the ProtoLite environment.
+ *
+ * <p>The test mechanism employed here is based on the pattern in
+ * {@code com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
+ */
+public class ExtensionRegistryFactoryTest extends TestCase {
+
+  // A classloader which blacklists some non-Lite classes.
+  private static final ClassLoader LITE_CLASS_LOADER = getLiteOnlyClassLoader();
+
+  /**
+   * Defines the set of test methods which will be run.
+   */
+  static interface RegistryTests {
+    void testCreate();
+    void testEmpty();
+    void testIsFullRegistry();
+    void testAdd();
+    void testAdd_immutable();
+  }
+
+  /**
+   * Test implementations for the non-Lite usage of ExtensionRegistryFactory.
+   */
+  public static class InnerTest implements RegistryTests {
+
+    @Override
+    public void testCreate() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+
+      assertEquals(registry.getClass(), ExtensionRegistry.class);
+    }
+
+    @Override
+    public void testEmpty() {
+      ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
+
+      assertEquals(emptyRegistry.getClass(), ExtensionRegistry.class);
+      assertEquals(emptyRegistry, ExtensionRegistry.EMPTY_REGISTRY);
+    }
+
+    @Override
+    public void testIsFullRegistry() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+      assertTrue(ExtensionRegistryFactory.isFullRegistry(registry));
+    }
+
+    @Override
+    public void testAdd() {
+      ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance();
+      NonNestedExtensionLite.registerAllExtensions(registry1);
+      registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
+
+      ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance();
+      NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
+      registry2.add(NonNestedExtension.nonNestedExtension);
+
+      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"));
+      GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
+      extension = registry1.findLiteExtensionByNumber(
+          NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
+      assertNotNull("Extension registered in lite registry", extension);
+
+      assertTrue("Test is using a non-lite extension",
+          GeneratedMessage.GeneratedExtension.class.isAssignableFrom(
+          NonNestedExtension.nonNestedExtension.getClass()));
+      assertNotNull("Extension is registered in masqueraded full registry",
+          fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
+    }
+
+    @Override
+    public void testAdd_immutable() {
+      ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance().getUnmodifiable();
+      try {
+        NonNestedExtensionLite.registerAllExtensions(registry1);
+        fail();
+      } catch (UnsupportedOperationException expected) {}
+      try {
+        registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
+        fail();
+      } catch (UnsupportedOperationException expected) {}
+
+      ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance().getUnmodifiable();
+      try {
+        NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
+        fail();
+      } catch (IllegalArgumentException expected) {}
+      try {
+        registry2.add(NonNestedExtension.nonNestedExtension);
+        fail();
+      } catch (IllegalArgumentException expected) {}
+    }
+  }
+
+  /**
+   * Test implementations for the Lite usage of ExtensionRegistryFactory.
+   */
+  public static final class InnerLiteTest implements RegistryTests {
+
+    @Override
+    public void testCreate() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+
+      assertEquals(registry.getClass(), ExtensionRegistryLite.class);
+    }
+
+    @Override
+    public void testEmpty() {
+      ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
+
+      assertEquals(emptyRegistry.getClass(), ExtensionRegistryLite.class);
+      assertEquals(emptyRegistry, ExtensionRegistryLite.EMPTY_REGISTRY_LITE);
+    }
+
+    @Override
+    public void testIsFullRegistry() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+      assertFalse(ExtensionRegistryFactory.isFullRegistry(registry));
+    }
+
+    @Override
+    public void testAdd() {
+      ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+      NonNestedExtensionLite.registerAllExtensions(registry);
+      GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
+          extension = registry.findLiteExtensionByNumber(
+              NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
+      assertNotNull("Extension is registered in Lite registry", extension);
+    }
+
+    @Override
+    public void testAdd_immutable() {
+      ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance().getUnmodifiable();
+      try {
+        NonNestedExtensionLite.registerAllExtensions(registry);
+        fail();
+      } catch (UnsupportedOperationException expected) {}
+    }
+  }
+
+  /**
+   * Defines a suite of tests which the JUnit3 runner retrieves by reflection.
+   */
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    for (Method method : RegistryTests.class.getMethods()) {
+      suite.addTest(TestSuite.createTest(ExtensionRegistryFactoryTest.class, method.getName()));
+    }
+    return suite;
+  }
+
+  /**
+   * Sequentially runs first the Lite and then the non-Lite test variant via classloader
+   * manipulation.
+   */
+  @Override
+  public void runTest() throws Exception {
+    ClassLoader storedClassLoader = Thread.currentThread().getContextClassLoader();
+    Thread.currentThread().setContextClassLoader(LITE_CLASS_LOADER);
+    try {
+      runTestMethod(LITE_CLASS_LOADER, InnerLiteTest.class);
+    } finally {
+      Thread.currentThread().setContextClassLoader(storedClassLoader);
+    }
+    try {
+      runTestMethod(storedClassLoader, InnerTest.class);
+    } finally {
+      Thread.currentThread().setContextClassLoader(storedClassLoader);
+    }
+  }
+
+  private void runTestMethod(ClassLoader classLoader, Class<? extends RegistryTests> testClass)
+      throws Exception {
+    classLoader.loadClass(ExtensionRegistryFactory.class.getName());
+    Class<?> test = classLoader.loadClass(testClass.getName());
+    String testName = getName();
+    test.getMethod(testName).invoke(test.newInstance());
+  }
+
+  /**
+   * Constructs a custom ClassLoader blacklisting the classes which are inspected in the SUT
+   * to 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)));
+
+    // 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()) {
+      @Override
+      public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        if (classNamesNotInLite.contains(name)) {
+          throw new ClassNotFoundException("Class deliberately blacklisted by test.");
+        }
+        Class<?> loadedClass = null;
+        try {
+          loadedClass = findLoadedClass(name);
+          if (loadedClass == null) {
+            loadedClass = findClass(name);
+            if (resolve) {
+              resolveClass(loadedClass);
+            }
+          }
+        } catch (ClassNotFoundException e) {
+          loadedClass = super.loadClass(name, resolve);
+        }
+        return loadedClass;
+      }
+    };
+  }
+}
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 eaeec0b..42da5bb 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -31,6 +31,8 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
 import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
@@ -44,9 +46,9 @@
  * non-message fields.
  */
 public class FieldPresenceTest extends TestCase {
-  private static boolean hasMethod(Class clazz, String name) {
+  private static boolean hasMethod(Class<?> clazz, String name) {
     try {
-      if (clazz.getMethod(name, new Class[]{}) != null) {
+      if (clazz.getMethod(name) != null) {
         return true;
       } else {
         return false;
@@ -56,90 +58,84 @@
     }
   }
 
-  private static boolean isHasMethodRemoved(
-      Class classWithFieldPresence,
-      Class classWithoutFieldPresence,
+  private static void assertHasMethodRemoved(
+      Class<?> classWithFieldPresence,
+      Class<?> classWithoutFieldPresence,
       String camelName) {
-    return hasMethod(classWithFieldPresence, "get" + camelName)
-        && hasMethod(classWithFieldPresence, "has" + camelName)
-        && hasMethod(classWithoutFieldPresence, "get" + camelName)
-        && !hasMethod(classWithoutFieldPresence, "has" + camelName);
+    assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
+    assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
+    assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
+    assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
   }
 
   public void testHasMethod() {
     // Optional non-message fields don't have a hasFoo() method generated.
-    assertTrue(isHasMethodRemoved(
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OptionalInt32"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalInt32");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OptionalString"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalString");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OptionalBytes"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalBytes");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OptionalNestedEnum"));
+        "OptionalNestedEnum");
 
-    assertTrue(isHasMethodRemoved(
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OptionalInt32"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalInt32");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OptionalString"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalString");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OptionalBytes"));
-    assertTrue(isHasMethodRemoved(
+        "OptionalBytes");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OptionalNestedEnum"));
+        "OptionalNestedEnum");
 
     // message fields still have the hasFoo() method generated.
     assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
     assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
 
-    // oneof fields don't have hasFoo() methods (even for message types).
-    assertTrue(isHasMethodRemoved(
+    // oneof fields don't have hasFoo() methods for non-message types.
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OneofUint32"));
-    assertTrue(isHasMethodRemoved(
+        "OneofUint32");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OneofString"));
-    assertTrue(isHasMethodRemoved(
+        "OneofString");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.class,
         TestAllTypes.class,
-        "OneofBytes"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.class,
-        TestAllTypes.class,
-        "OneofNestedMessage"));
+        "OneofBytes");
+    assertFalse(TestAllTypes.newBuilder().build().hasOneofNestedMessage());
+    assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
 
-    assertTrue(isHasMethodRemoved(
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OneofUint32"));
-    assertTrue(isHasMethodRemoved(
+        "OneofUint32");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OneofString"));
-    assertTrue(isHasMethodRemoved(
+        "OneofString");
+    assertHasMethodRemoved(
         UnittestProto.TestAllTypes.Builder.class,
         TestAllTypes.Builder.class,
-        "OneofBytes"));
-    assertTrue(isHasMethodRemoved(
-        UnittestProto.TestAllTypes.Builder.class,
-        TestAllTypes.Builder.class,
-        "OneofNestedMessage"));
+        "OneofBytes");
   }
 
   public void testOneofEquals() throws Exception {
@@ -152,6 +148,26 @@
     assertFalse(message1.equals(message2));
   }
 
+  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());
+
+    // Set default instance to the field.
+    builder.setOptionalLazyMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    message = builder.build();
+    assertTrue(message.hasOptionalLazyMessage());
+    assertEquals(2, message.getSerializedSize());
+
+    // Test parse zero-length from wire sets the presence.
+    TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteString());
+    assertTrue(parsed.hasOptionalLazyMessage());
+    assertEquals(message.getOptionalLazyMessage(), parsed.getOptionalLazyMessage());
+  }
+
   public void testFieldPresence() {
     // Optional non-message fields set to their default value are treated the
     // same way as not set.
@@ -232,24 +248,72 @@
     assertTrue(message.hasField(optionalNestedEnumField));
     assertEquals(4, message.getAllFields().size());
   }
-  
+
+  public void testFieldPresenceDynamicMessage() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
+    FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
+    FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
+    FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+    EnumDescriptor enumDescriptor = optionalNestedEnumField.getEnumType();
+    EnumValueDescriptor defaultEnumValueDescriptor = enumDescriptor.getValues().get(0);
+    EnumValueDescriptor nonDefaultEnumValueDescriptor = enumDescriptor.getValues().get(1);
+
+    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());
+
+    // Field set to non-default value is seen as present.
+    message =
+        defaultInstance
+            .newBuilderForType()
+            .setField(optionalInt32Field, 1)
+            .setField(optionalStringField, "x")
+            .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());
+
+    // Field set to default value is seen as not present.
+    message = message.toBuilder()
+            .setField(optionalInt32Field, 0)
+            .setField(optionalStringField, "")
+            .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());
+  }
+
   public void testMessageField() {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     assertFalse(builder.hasOptionalNestedMessage());
     assertFalse(builder.build().hasOptionalNestedMessage());
-    
+
     TestAllTypes.NestedMessage.Builder nestedBuilder =
         builder.getOptionalNestedMessageBuilder();
     assertTrue(builder.hasOptionalNestedMessage());
     assertTrue(builder.build().hasOptionalNestedMessage());
-    
+
     nestedBuilder.setValue(1);
     assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
-    
+
     builder.clearOptionalNestedMessage();
     assertFalse(builder.hasOptionalNestedMessage());
     assertFalse(builder.build().hasOptionalNestedMessage());
-    
+
     // 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());
@@ -340,34 +404,4 @@
     assertTrue(builder.buildPartial().isInitialized());
   }
 
-  
-  // Test that unknown fields are dropped.
-  public void testUnknownFields() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    builder.setOptionalInt32(1234);
-    builder.addRepeatedInt32(5678);
-    TestAllTypes message = builder.build();
-    ByteString data = message.toByteString();
-    
-    TestOptionalFieldsOnly optionalOnlyMessage =
-        TestOptionalFieldsOnly.parseFrom(data);
-    // UnknownFieldSet should be empty.
-    assertEquals(
-        0, optionalOnlyMessage.getUnknownFields().toByteString().size());
-    assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
-    message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString());
-    assertEquals(1234, message.getOptionalInt32());
-    // The repeated field is discarded because it's unknown to the optional-only
-    // message.
-    assertEquals(0, message.getRepeatedInt32Count());
-    
-    DynamicMessage dynamicOptionalOnlyMessage =
-        DynamicMessage.getDefaultInstance(
-            TestOptionalFieldsOnly.getDescriptor())
-        .getParserForType().parseFrom(data);
-    assertEquals(
-        0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size());
-    assertEquals(optionalOnlyMessage.toByteString(),
-        dynamicOptionalOnlyMessage.toByteString());
-  }
 }
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 a5e6542..903a79d 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -32,61 +32,48 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
+import com.google.protobuf.Internal.FloatList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link FloatArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class FloatArrayListTest extends TestCase {
-  
-  private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
+
+  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 {
     list = new FloatArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(FloatArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addFloat(2);
+    list.addFloat(3);
     list.addFloat(4);
-    list.addFloat(6);
-    list.addFloat(8);
+    list.addFloat(5);
+    list.addFloat(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
-  public void testCopyConstructor() {
-    FloatArrayList copy = new FloatArrayList(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
 
-    copy = new FloatArrayList(FloatArrayList.emptyList());
-    assertEquals(FloatArrayList.emptyList(), copy);
-    
-    copy = new FloatArrayList(asList(1F, 2F, 3F));
-    assertEquals(asList(1F, 2F, 3F), copy);
-
-    copy = new FloatArrayList(Collections.<Float>emptyList());
-    assertEquals(FloatArrayList.emptyList(), copy);
-  }
-  
   public void testModificationWithIteration() {
     list.addAll(asList(1F, 2F, 3F, 4F));
     Iterator<Float> iterator = list.iterator();
@@ -95,7 +82,7 @@
     assertEquals(1F, (float) iterator.next());
     list.set(0, 1F);
     assertEquals(2F, (float) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -103,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0F);
     try {
@@ -113,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1F, (float) TERTIARY_LIST.get(0));
     assertEquals(2F, (float) TERTIARY_LIST.get(1));
     assertEquals(3F, (float) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -133,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetFloat() {
     assertEquals(1F, TERTIARY_LIST.getFloat(0));
     assertEquals(2F, TERTIARY_LIST.getFloat(1));
     assertEquals(3F, TERTIARY_LIST.getFloat(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -153,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, FloatArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addFloat(2);
+    list.addFloat(3);
     list.addFloat(4);
     list.addFloat(6);
     list.addFloat(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16F);
+
+    list.add(17F);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addFloat(2);
     list.addFloat(4);
-    
-    assertEquals(2F, (float) list.set(0, 0F));
-    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(2F, (float) list.set(0, 3F));
+    assertEquals(3F, list.getFloat(0));
 
     assertEquals(4F, (float) list.set(1, 0F));
     assertEquals(0F, list.getFloat(1));
-    
+
     try {
       list.set(-1, 0F);
       fail();
@@ -196,17 +183,17 @@
       // expected
     }
   }
-  
+
   public void testSetFloat() {
-    list.addFloat(2);
-    list.addFloat(4);
-    
-    assertEquals(2F, list.setFloat(0, 0));
+    list.addFloat(1);
+    list.addFloat(3);
+
+    assertEquals(1F, list.setFloat(0, 0));
     assertEquals(0F, list.getFloat(0));
 
-    assertEquals(4F, list.setFloat(1, 0));
+    assertEquals(3F, list.setFloat(1, 0));
     assertEquals(0F, list.getFloat(1));
-    
+
     try {
       list.setFloat(-1, 0);
       fail();
@@ -221,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -231,28 +218,30 @@
     assertTrue(list.add(3F));
     list.add(0, 4F);
     assertEquals(asList(4F, 2F, 3F), list);
-    
+
     list.add(0, 1F);
     list.add(0, 0F);
     // Force a resize by getting up to 11 elements.
     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);
-    
+    assertEquals(
+        asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F),
+        list);
+
     try {
       list.add(-1, 5F);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5F);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddFloat() {
     assertEquals(0, list.size());
 
@@ -262,7 +251,7 @@
     list.addFloat(3);
     assertEquals(asList(2F, 3F), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -270,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1F, (float) list.get(0));
     assertEquals(1F, list.getFloat(0));
-    
+
     assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list);
 
     assertFalse(list.addAll(Collections.<Float>emptyList()));
     assertFalse(list.addAll(FloatArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1F, (float) list.remove(0));
@@ -294,96 +283,110 @@
 
     assertEquals(2F, (float) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
+  public void testRemoveEndOfCapacity() {
+    FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addFloat(3);
+    toRemove.remove(0);
+    assertEquals(0, toRemove.size());
+  }
+
+  public void testSublistRemoveEndOfCapacity() {
+    FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addFloat(3);
+    toRemove.subList(0, 1).clear();
+    assertEquals(0, toRemove.size());
+  }
+
   private void assertImmutable(FloatArrayList list) {
     if (list.contains(1F)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new FloatArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addFloat(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -397,63 +400,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setFloat(0, 0);
       fail();
@@ -461,10 +464,10 @@
       // expected
     }
   }
-  
-  private static FloatArrayList newImmutableFloatArrayList(int... elements) {
+
+  private static FloatArrayList newImmutableFloatArrayList(float... elements) {
     FloatArrayList list = new FloatArrayList();
-    for (int element : elements) {
+    for (float element : elements) {
       list.addFloat(element);
     }
     list.makeImmutable();
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
index a92ba37..b7eaebf 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
@@ -41,7 +41,7 @@
  */
 public class ForceFieldBuildersPreRun implements Runnable {
 
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
+  @Override
   public void run() {
     GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
   }
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 70812b9..c9ebe7f 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -32,19 +32,14 @@
 
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.test.UnittestImport;
 import protobuf_unittest.EnumWithNoOuter;
 import protobuf_unittest.MessageWithNoOuter;
 import protobuf_unittest.MultipleFilesTestProto;
 import protobuf_unittest.NestedExtension.MyNestedExtension;
-import protobuf_unittest.NestedExtensionLite.MyNestedExtensionLite;
 import protobuf_unittest.NonNestedExtension;
 import protobuf_unittest.NonNestedExtension.MessageToBeExtended;
 import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
-import protobuf_unittest.NonNestedExtensionLite;
-import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
-import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
 import protobuf_unittest.OuterClassNameTest2OuterClass;
 import protobuf_unittest.OuterClassNameTest3OuterClass;
 import protobuf_unittest.OuterClassNameTestOuterClass;
@@ -65,9 +60,6 @@
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.ObjectInputStream;
@@ -76,6 +68,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Unit test for generated messages and generated code.  See also
@@ -620,6 +613,21 @@
     TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
   }
 
+  public void testUnsetRepeatedExtensionGetField() {
+    TestAllExtensions message = TestAllExtensions.getDefaultInstance();
+    Object value;
+
+    value = message.getField(UnittestProto.repeatedStringExtension.getDescriptor());
+    assertTrue(value instanceof List);
+    assertTrue(((List<?>) value).isEmpty());
+    assertIsUnmodifiable((List<?>) value);
+
+    value = message.getField(UnittestProto.repeatedNestedMessageExtension.getDescriptor());
+    assertTrue(value instanceof List);
+    assertTrue(((List<?>) value).isEmpty());
+    assertIsUnmodifiable((List<?>) value);
+  }
+
   public void testExtensionReflectionGetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestUtil.setAllExtensions(builder);
@@ -699,70 +707,6 @@
   }
 
   // =================================================================
-  // Lite Extensions.
-
-  // We test lite extensions directly because they have a separate
-  // implementation from full extensions.  In contrast, we do not test
-  // lite fields directly since they are implemented exactly the same as
-  // regular fields.
-
-  public void testLiteExtensionMessageOrBuilder() throws Exception {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestUtil.assertAllExtensionsSet(builder);
-
-    TestAllExtensionsLite message = builder.build();
-    TestUtil.assertAllExtensionsSet(message);
-  }
-
-  public void testLiteExtensionRepeatedSetters() throws Exception {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestUtil.modifyRepeatedExtensions(builder);
-    TestUtil.assertRepeatedExtensionsModified(builder);
-
-    TestAllExtensionsLite message = builder.build();
-    TestUtil.assertRepeatedExtensionsModified(message);
-  }
-
-  public void testLiteExtensionDefaults() throws Exception {
-    TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
-    TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
-  }
-
-  public void testClearLiteExtension() throws Exception {
-    // clearExtension() is not actually used in TestUtil, so try it manually.
-    assertFalse(
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
-        .clearExtension(UnittestLite.optionalInt32ExtensionLite)
-        .hasExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(0,
-      TestAllExtensionsLite.newBuilder()
-        .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
-        .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
-        .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
-  }
-
-  public void testLiteExtensionCopy() throws Exception {
-    TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
-    TestAllExtensionsLite copy =
-        TestAllExtensionsLite.newBuilder(original).build();
-    TestUtil.assertAllExtensionsSet(copy);
-  }
-
-  public void testLiteExtensionMergeFrom() throws Exception {
-    TestAllExtensionsLite original =
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
-    TestAllExtensionsLite merged =
-        TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
-    assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(
-        1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
-  }
-
-  // =================================================================
   // multiple_files_test
 
   // Test that custom options of an file level enum are properly initialized.
@@ -910,15 +854,9 @@
   }
 
   public void testEnumValues() {
-     assertEquals(
-         TestAllTypes.NestedEnum.BAR.getNumber(),
-         TestAllTypes.NestedEnum.BAR_VALUE);
-    assertEquals(
-        TestAllTypes.NestedEnum.BAZ.getNumber(),
-        TestAllTypes.NestedEnum.BAZ_VALUE);
-    assertEquals(
-        TestAllTypes.NestedEnum.FOO.getNumber(),
-        TestAllTypes.NestedEnum.FOO_VALUE);
+    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());
   }
 
   public void testNonNestedExtensionInitialization() {
@@ -935,16 +873,6 @@
                  MyNestedExtension.recursiveExtension.getDescriptor().getName());
   }
 
-  public void testNonNestedExtensionLiteInitialization() {
-    assertTrue(NonNestedExtensionLite.nonNestedExtensionLite
-               .getMessageDefaultInstance() instanceof MyNonNestedExtensionLite);
-  }
-
-  public void testNestedExtensionLiteInitialization() {
-    assertTrue(MyNestedExtensionLite.recursiveExtensionLite
-               .getMessageDefaultInstance() instanceof MessageLiteToBeExtended);
-  }
-
   public void testInvalidations() throws Exception {
     GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
     TestAllTypes.NestedMessage nestedMessage1 =
@@ -957,7 +885,7 @@
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
 
     TestAllTypes.Builder builder = (TestAllTypes.Builder)
-        ((GeneratedMessage) TestAllTypes.getDefaultInstance()).
+        ((AbstractMessage) TestAllTypes.getDefaultInstance()).
             newBuilderForType(mockParent);
     builder.setOptionalInt32(1);
     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
@@ -1012,7 +940,7 @@
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
 
     TestAllExtensions.Builder builder = (TestAllExtensions.Builder)
-        ((GeneratedMessage) TestAllExtensions.getDefaultInstance()).
+        ((AbstractMessage) TestAllExtensions.getDefaultInstance()).
             newBuilderForType(mockParent);
 
     builder.addExtension(UnittestProto.repeatedInt32Extension, 1);
@@ -1306,51 +1234,51 @@
       assertFalse(builder.clearFooInt().hasFooInt());
       TestOneof2 message2 = builder.build();
       assertFalse(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 0);
+      assertEquals(0, message2.getFooInt());
     }
 
     // Enum
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
+      assertEquals(TestOneof2.NestedEnum.FOO, builder.getFooEnum());
       assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
-      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      assertEquals(TestOneof2.NestedEnum.BAR, builder.getFooEnum());
       TestOneof2 message = builder.buildPartial();
       assertTrue(message.hasFooEnum());
-      assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      assertEquals(TestOneof2.NestedEnum.BAR, message.getFooEnum());
 
       assertFalse(builder.clearFooEnum().hasFooEnum());
       TestOneof2 message2 = builder.build();
       assertFalse(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
+      assertEquals(TestOneof2.NestedEnum.FOO, message2.getFooEnum());
     }
 
     // String
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooString(), "");
+      assertEquals("", builder.getFooString());
       builder.setFooString("foo");
       assertTrue(builder.hasFooString());
-      assertEquals(builder.getFooString(), "foo");
+      assertEquals("foo", builder.getFooString());
       TestOneof2 message = builder.buildPartial();
       assertTrue(message.hasFooString());
-      assertEquals(message.getFooString(), "foo");
+      assertEquals("foo", message.getFooString());
       assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
 
       assertFalse(builder.clearFooString().hasFooString());
       TestOneof2 message2 = builder.buildPartial();
       assertFalse(message2.hasFooString());
-      assertEquals(message2.getFooString(), "");
+      assertEquals("", message2.getFooString());
       assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
 
       // Get method should not change the oneof value.
       builder.setFooInt(123);
-      assertEquals(builder.getFooString(), "");
+      assertEquals("", builder.getFooString());
       assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
       assertEquals(123, builder.getFooInt());
 
       message = builder.build();
-      assertEquals(message.getFooString(), "");
+      assertEquals("", message.getFooString());
       assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
       assertEquals(123, message.getFooInt());
     }
@@ -1358,38 +1286,38 @@
     // Cord
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooCord(), "");
+      assertEquals("", builder.getFooCord());
       builder.setFooCord("foo");
       assertTrue(builder.hasFooCord());
-      assertEquals(builder.getFooCord(), "foo");
+      assertEquals("foo", builder.getFooCord());
       TestOneof2 message = builder.buildPartial();
       assertTrue(message.hasFooCord());
-      assertEquals(message.getFooCord(), "foo");
+      assertEquals("foo", message.getFooCord());
       assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
 
       assertFalse(builder.clearFooCord().hasFooCord());
       TestOneof2 message2 = builder.build();
       assertFalse(message2.hasFooCord());
-      assertEquals(message2.getFooCord(), "");
+      assertEquals("", message2.getFooCord());
       assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
     }
 
     // StringPiece
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooStringPiece(), "");
+      assertEquals("", builder.getFooStringPiece());
       builder.setFooStringPiece("foo");
       assertTrue(builder.hasFooStringPiece());
-      assertEquals(builder.getFooStringPiece(), "foo");
+      assertEquals("foo", builder.getFooStringPiece());
       TestOneof2 message = builder.buildPartial();
       assertTrue(message.hasFooStringPiece());
-      assertEquals(message.getFooStringPiece(), "foo");
+      assertEquals("foo", message.getFooStringPiece());
       assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
 
       assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
       TestOneof2 message2 = builder.build();
       assertFalse(message2.hasFooStringPiece());
-      assertEquals(message2.getFooStringPiece(), "");
+      assertEquals("", message2.getFooStringPiece());
       assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
     }
 
@@ -1397,20 +1325,20 @@
     {
       // set
       TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooMessage().getQuxInt(), 0);
+      assertEquals(0, builder.getFooMessage().getQuxInt());
       builder.setFooMessage(
           TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
       assertTrue(builder.hasFooMessage());
-      assertEquals(builder.getFooMessage().getQuxInt(), 234);
+      assertEquals(234, builder.getFooMessage().getQuxInt());
       TestOneof2 message = builder.buildPartial();
       assertTrue(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 234);
+      assertEquals(234, message.getFooMessage().getQuxInt());
 
       // clear
       assertFalse(builder.clearFooMessage().hasFooString());
       message = builder.build();
       assertFalse(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 0);
+      assertEquals(0, message.getFooMessage().getQuxInt());
 
       // nested builder
       builder = TestOneof2.newBuilder();
@@ -1419,10 +1347,10 @@
       assertFalse(builder.hasFooMessage());
       builder.getFooMessageBuilder().setQuxInt(123);
       assertTrue(builder.hasFooMessage());
-      assertEquals(builder.getFooMessage().getQuxInt(), 123);
+      assertEquals(123, builder.getFooMessage().getQuxInt());
       message = builder.build();
       assertTrue(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 123);
+      assertEquals(123, message.getFooMessage().getQuxInt());
     }
 
     // LazyMessage is tested in LazyMessageLiteTest.java
@@ -1435,7 +1363,7 @@
       TestOneof2 message = builder.setFooInt(123).build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
       assertTrue(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 123);
+      assertEquals(123, message2.getFooInt());
     }
 
     // String
@@ -1444,7 +1372,7 @@
       TestOneof2 message = builder.setFooString("foo").build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
       assertTrue(message2.hasFooString());
-      assertEquals(message2.getFooString(), "foo");
+      assertEquals("foo", message2.getFooString());
     }
 
     // Enum
@@ -1453,7 +1381,7 @@
       TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
       assertTrue(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
     }
 
     // Message
@@ -1463,7 +1391,7 @@
           TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
       TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
       assertTrue(message2.hasFooMessage());
-      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+      assertEquals(234, message2.getFooMessage().getQuxInt());
     }
   }
 
@@ -1475,7 +1403,7 @@
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
       assertTrue(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 123);
+      assertEquals(123, message2.getFooInt());
     }
 
     // String
@@ -1485,7 +1413,7 @@
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
       assertTrue(message2.hasFooString());
-      assertEquals(message2.getFooString(), "foo");
+      assertEquals("foo", message2.getFooString());
     }
 
     // Enum
@@ -1495,7 +1423,7 @@
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
       assertTrue(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
     }
 
     // Message
@@ -1506,7 +1434,7 @@
       ByteString serialized = message.toByteString();
       TestOneof2 message2 = TestOneof2.parseFrom(serialized);
       assertTrue(message2.hasFooMessage());
-      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+      assertEquals(234, message2.getFooMessage().getQuxInt());
     }
   }
 
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 3733eb3..d8e97d4 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -32,60 +32,47 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
+import com.google.protobuf.Internal.IntList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link IntArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class IntArrayListTest extends TestCase {
-  
-  private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
+
+  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 {
     list = new IntArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(IntArrayList.emptyList(), IntArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(IntArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addInt(2);
+    list.addInt(3);
     list.addInt(4);
-    list.addInt(6);
-    list.addInt(8);
+    list.addInt(5);
+    list.addInt(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
-  public void testCopyConstructor() {
-    IntArrayList copy = new IntArrayList(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
-
-    copy = new IntArrayList(IntArrayList.emptyList());
-    assertEquals(IntArrayList.emptyList(), copy);
-    
-    copy = new IntArrayList(asList(1, 2, 3));
-    assertEquals(asList(1, 2, 3), copy);
-
-    copy = new IntArrayList(Collections.<Integer>emptyList());
-    assertEquals(IntArrayList.emptyList(), copy);
-  }
 
   public void testModificationWithIteration() {
     list.addAll(asList(1, 2, 3, 4));
@@ -95,7 +82,7 @@
     assertEquals(1, (int) iterator.next());
     list.set(0, 1);
     assertEquals(2, (int) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -113,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1, (int) TERTIARY_LIST.get(0));
     assertEquals(2, (int) TERTIARY_LIST.get(1));
     assertEquals(3, (int) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -133,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetInt() {
     assertEquals(1, TERTIARY_LIST.getInt(0));
     assertEquals(2, TERTIARY_LIST.getInt(1));
     assertEquals(3, TERTIARY_LIST.getInt(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -153,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, IntArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addInt(2);
+    list.addInt(3);
     list.addInt(4);
     list.addInt(6);
     list.addInt(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16);
+
+    list.add(17);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addInt(2);
     list.addInt(4);
-    
-    assertEquals(2, (int) list.set(0, 0));
-    assertEquals(0, list.getInt(0));
+
+    assertEquals(2, (int) list.set(0, 3));
+    assertEquals(3, list.getInt(0));
 
     assertEquals(4, (int) list.set(1, 0));
     assertEquals(0, list.getInt(1));
-    
+
     try {
       list.set(-1, 0);
       fail();
@@ -196,17 +183,17 @@
       // expected
     }
   }
-  
+
   public void testSetInt() {
-    list.addInt(2);
-    list.addInt(4);
-    
-    assertEquals(2, list.setInt(0, 0));
+    list.addInt(1);
+    list.addInt(3);
+
+    assertEquals(1, list.setInt(0, 0));
     assertEquals(0, list.getInt(0));
 
-    assertEquals(4, list.setInt(1, 0));
+    assertEquals(3, list.setInt(1, 0));
     assertEquals(0, list.getInt(1));
-    
+
     try {
       list.setInt(-1, 0);
       fail();
@@ -221,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -231,28 +218,30 @@
     assertTrue(list.add(3));
     list.add(0, 4);
     assertEquals(asList(4, 2, 3), list);
-    
+
     list.add(0, 1);
     list.add(0, 0);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
-      list.add(5 + i);
+      list.add(Integer.valueOf(5 + i));
     }
-    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
-    
+    assertEquals(
+        asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10),
+        list);
+
     try {
       list.add(-1, 5);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddInt() {
     assertEquals(0, list.size());
 
@@ -262,7 +251,7 @@
     list.addInt(3);
     assertEquals(asList(2, 3), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -270,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1, (int) list.get(0));
     assertEquals(1, list.getInt(0));
-    
+
     assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
     assertEquals(asList(1, 2, 3, 4, 5, 6), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
 
     assertFalse(list.addAll(Collections.<Integer>emptyList()));
     assertFalse(list.addAll(IntArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1, (int) list.remove(0));
@@ -294,96 +283,110 @@
 
     assertEquals(2, (int) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
+  public void testRemoveEndOfCapacity() {
+    IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addInt(3);
+    toRemove.remove(0);
+    assertEquals(0, toRemove.size());
+  }
+
+  public void testSublistRemoveEndOfCapacity() {
+    IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addInt(3);
+    toRemove.subList(0, 1).clear();
+    assertEquals(0, toRemove.size());
+  }
+
   private void assertImmutable(IntArrayList list) {
     if (list.contains(1)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new IntArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addInt(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -397,63 +400,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setInt(0, 0);
       fail();
@@ -461,7 +464,7 @@
       // expected
     }
   }
-  
+
   private static IntArrayList newImmutableIntArrayList(int... elements) {
     IntArrayList list = new IntArrayList();
     for (int element : elements) {
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 8751baa..756049b 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -30,12 +30,18 @@
 
 package com.google.protobuf;
 
+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;
+import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.testBytes;
+
+import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
 import com.google.protobuf.IsValidUtf8TestUtil.Shard;
 
 import junit.framework.TestCase;
 
-import java.io.UnsupportedEncodingException;
-
 /**
  * Tests cases for {@link ByteString#isValidUtf8()}. This includes three
  * brute force tests that actually test every permutation of one byte, two byte,
@@ -51,31 +57,33 @@
  * @author martinrb@google.com (Martin Buchholz)
  */
 public class IsValidUtf8Test extends TestCase {
-
   /**
    * Tests that round tripping of all two byte permutations work.
    */
-  public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException {
-    IsValidUtf8TestUtil.testBytes(1,
-        IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+  public void testIsValidUtf8_1Byte() {
+    testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
   }
 
   /**
    * Tests that round tripping of all two byte permutations work.
    */
-  public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException {
-    IsValidUtf8TestUtil.testBytes(2,
-        IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+  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);
+    testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
   }
 
   /**
    * Tests that round tripping of all three byte permutations work.
    */
-  public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException {
+  public void testIsValidUtf8_3Bytes() {
     // Travis' OOM killer doesn't like this test
     if (System.getenv("TRAVIS") == null) {
-      IsValidUtf8TestUtil.testBytes(3,
-          IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+      testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+      testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+      testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
     }
   }
 
@@ -85,8 +93,7 @@
    * {@link IsValidUtf8FourByteTest} is used for full coverage. This method
    * tests specific four-byte cases.
    */
-  public void testIsValidUtf8_4BytesSamples()
-      throws UnsupportedEncodingException {
+  public void testIsValidUtf8_4BytesSamples() {
     // Valid 4 byte.
     assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
 
@@ -119,9 +126,7 @@
     assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
 
     // Mixed string
-    assertTrue(
-        asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62")
-        .isValidUtf8());
+    assertTrue(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8());
 
     // Not a valid string
     assertInvalidUtf8(-1, 0, -1, 0);
@@ -135,36 +140,35 @@
     return realBytes;
   }
 
-  private ByteString toByteString(int... bytes) {
-    return ByteString.copyFrom(toByteArray(bytes));
-  }
-
-  private void assertValidUtf8(int[] bytes, boolean not) {
+  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));
-    ByteString lit = ByteString.copyFrom(realBytes);
-    ByteString sub = lit.substring(0, bytes.length);
-    assertTrue(not ^ lit.isValidUtf8());
+    ByteString leaf = factory.newByteString(realBytes);
+    ByteString sub = leaf.substring(0, bytes.length);
+    assertTrue(not ^ leaf.isValidUtf8());
     assertTrue(not ^ sub.isValidUtf8());
     ByteString[] ropes = {
-      RopeByteString.newInstanceForTest(ByteString.EMPTY, lit),
-      RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
-      RopeByteString.newInstanceForTest(lit, ByteString.EMPTY),
-      RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
-      RopeByteString.newInstanceForTest(sub, lit)
-    };
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
+        RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY),
+        RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
+        RopeByteString.newInstanceForTest(sub, leaf)};
     for (ByteString rope : ropes) {
       assertTrue(not ^ rope.isValidUtf8());
     }
   }
 
   private void assertValidUtf8(int... bytes) {
-    assertValidUtf8(bytes, false);
+    assertValidUtf8(LITERAL_FACTORY, bytes, false);
+    assertValidUtf8(HEAP_NIO_FACTORY, bytes, false);
+    assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false);
   }
 
   private void assertInvalidUtf8(int... bytes) {
-    assertValidUtf8(bytes, true);
+    assertValidUtf8(LITERAL_FACTORY, bytes, true);
+    assertValidUtf8(HEAP_NIO_FACTORY, bytes, true);
+    assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true);
   }
 
   private static ByteString asBytes(String s) {
@@ -177,7 +181,6 @@
     for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
       actual += shard.expected;
     }
-    assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT,
-        actual);
+    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 321669f..1bcf63e 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -30,9 +30,13 @@
 
 package com.google.protobuf;
 
-import static junit.framework.Assert.*;
+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 java.io.UnsupportedEncodingException;
+import java.lang.ref.SoftReference;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
@@ -52,64 +56,105 @@
  * @author jonp@google.com (Jon Perlow)
  * @author martinrb@google.com (Martin Buchholz)
  */
-class IsValidUtf8TestUtil {
-  private static Logger logger = Logger.getLogger(
-      IsValidUtf8TestUtil.class.getName());
+final class IsValidUtf8TestUtil {
+  private static Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
+
+  private IsValidUtf8TestUtil() {}
+
+  static interface ByteStringFactory {
+    ByteString newByteString(byte[] bytes);
+  }
+
+  static final ByteStringFactory LITERAL_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      return ByteString.wrap(bytes);
+    }
+  };
+
+  static final ByteStringFactory HEAP_NIO_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      return new NioByteString(ByteBuffer.wrap(bytes));
+    }
+  };
+
+  private static ThreadLocal<SoftReference<ByteBuffer>> directBuffer =
+      new ThreadLocal<SoftReference<ByteBuffer>>();
+
+  /**
+   * Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this
+   * uses a thread local direct buffer. This means that each call will overwrite the buffer's
+   * contents from the previous call, so the calling code must be careful not to continue using
+   * a buffer returned from a previous invocation.
+   */
+  static final ByteStringFactory DIRECT_NIO_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      SoftReference<ByteBuffer> ref = directBuffer.get();
+      ByteBuffer buffer = ref == null ? null : ref.get();
+      if (buffer == null || buffer.capacity() < bytes.length) {
+        buffer = ByteBuffer.allocateDirect(bytes.length);
+        directBuffer.set(new SoftReference<ByteBuffer>(buffer));
+      }
+      buffer.clear();
+      buffer.put(bytes);
+      buffer.flip();
+      return new NioByteString(buffer);
+    }
+  };
 
   // 128 - [chars 0x0000 to 0x007f]
-  static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
+  static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
 
   // 128
-  static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT =
-      ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+  static final long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
   // 1920 [chars 0x0080 to 0x07FF]
-  static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
+  static final long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
 
   // 18,304
-  static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
+  static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
       // Both bytes are one byte characters
       (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
       // The possible number of two byte characters
       TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
   // 2048
-  static long THREE_BYTE_SURROGATES = 2 * 1024;
+  static final long THREE_BYTE_SURROGATES = 2 * 1024;
 
   // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
-  static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
+  static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
       0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
 
   // 2,650,112
-  static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
+  static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
       // All one byte characters
       (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
       // One two byte character and a one byte character
-      2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
-       // Three byte characters
+      2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      // Three byte characters
       THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
   // 1,048,576 [chars 0x10000L to 0x10FFFF]
-  static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
+  static final long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
 
   // 289,571,839
-  static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
+  static final long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
       // All one byte characters
       (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
       // One and three byte characters
-      2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
       // Two two byte characters
       TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
       // Permutations of one and two byte characters
-      3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+      * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+      +
       // Four byte characters
       FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
-  static class Shard {
+  static final class Shard {
     final long index;
     final long start;
     final long lim;
@@ -138,7 +183,7 @@
 
     // 97-111 are all 2342912
     for (int i = 97; i <= 111; i++) {
-     expected[i] = 2342912;
+      expected[i] = 2342912;
     }
 
     // 113-117 are all 1048576
@@ -158,22 +203,18 @@
     return expected;
   }
 
-  static final List<Shard> FOUR_BYTE_SHARDS = generateFourByteShards(
-      128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
+  static final List<Shard> FOUR_BYTE_SHARDS =
+      generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
 
 
-  private static List<Shard> generateFourByteShards(
-      int numShards, long[] expected) {
+  private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
     assertEquals(numShards, expected.length);
     List<Shard> shards = new ArrayList<Shard>(numShards);
     long LIM = 1L << 32;
     long increment = LIM / numShards;
     assertTrue(LIM % numShards == 0);
     for (int i = 0; i < numShards; i++) {
-      shards.add(new Shard(i,
-          increment * i,
-          increment * (i + 1),
-          expected[i]));
+      shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
     }
     return shards;
   }
@@ -182,12 +223,12 @@
    * Helper to run the loop to test all the permutations for the number of bytes
    * specified.
    *
+   * @param factory the factory for {@link ByteString} instances.
    * @param numBytes the number of bytes in the byte array
    * @param expectedCount the expected number of roundtrippable permutations
    */
-  static void testBytes(int numBytes, long expectedCount)
-      throws UnsupportedEncodingException {
-    testBytes(numBytes, expectedCount, 0, -1);
+  static void testBytes(ByteStringFactory factory, int numBytes, long expectedCount) {
+    testBytes(factory, numBytes, expectedCount, 0, -1);
   }
 
   /**
@@ -195,14 +236,15 @@
    * specified. This overload is useful for debugging to get the loop to start
    * at a certain character.
    *
+   * @param factory the factory for {@link ByteString} instances.
    * @param numBytes the number of bytes in the byte array
    * @param expectedCount the expected number of roundtrippable permutations
    * @param start the starting bytes encoded as a long as big-endian
    * @param lim the limit of bytes to process encoded as a long as big-endian,
    *     or -1 to mean the max limit for numBytes
    */
-  static void testBytes(int numBytes, long expectedCount, long start, long lim)
-      throws UnsupportedEncodingException {
+  static void testBytes(
+      ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
     Random rnd = new Random();
     byte[] bytes = new byte[numBytes];
 
@@ -217,7 +259,7 @@
         bytes[bytes.length - i - 1] = (byte) tmpByteChar;
         tmpByteChar = tmpByteChar >> 8;
       }
-      ByteString bs = ByteString.copyFrom(bytes);
+      ByteString bs = factory.newByteString(bytes);
       boolean isRoundTrippable = bs.isValidUtf8();
       String s = new String(bytes, Internal.UTF_8);
       byte[] bytesReencoded = s.getBytes(Internal.UTF_8);
@@ -231,19 +273,29 @@
       assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
       assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
 
+      try {
+        assertEquals(s, Utf8.decodeUtf8(bytes, 0, numBytes));
+      } catch (InvalidProtocolBufferException e) {
+        if (isRoundTrippable) {
+          System.out.println("Could not decode utf-8");
+          outputFailure(byteChar, bytes, bytesReencoded);
+        }
+      }
+
       // Test partial sequences.
       // Partition numBytes into three segments (not necessarily non-empty).
       int i = rnd.nextInt(numBytes);
       int j = rnd.nextInt(numBytes);
       if (j < i) {
-        int tmp = i; i = j; j = tmp;
+        int tmp = i;
+        i = j;
+        j = tmp;
       }
       int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
       int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
       int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
       if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
-        System.out.printf("state=%04x %04x %04x i=%d j=%d%n",
-                          state1, state2, state3, i, j);
+        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));
@@ -251,36 +303,24 @@
       // 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)));
+          RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
       assertSame(RopeByteString.class, rope.getClass());
 
-      ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope };
+      ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
       for (ByteString x : byteStrings) {
-        assertEquals(isRoundTrippable,
-                     x.isValidUtf8());
-        assertEquals(state3,
-                     x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
+        assertEquals(isRoundTrippable, x.isValidUtf8());
+        assertEquals(state3, x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
 
-        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));
+        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));
       }
 
       // ByteString reduplication should not affect its UTF-8 validity.
-      ByteString ropeADope =
-          RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
+      ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
       assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
 
       if (isRoundTrippable) {
@@ -288,8 +328,7 @@
       }
       count++;
       if (byteChar != 0 && byteChar % 1000000L == 0) {
-        logger.info("Processed " + (byteChar / 1000000L) +
-            " million characters");
+        logger.info("Processed " + (byteChar / 1000000L) + " million characters");
       }
     }
     logger.info("Round tripped " + countRoundTripped + " of " + count);
@@ -303,25 +342,26 @@
    * actual String class, it's possible for incompatibilities to develop
    * (although unlikely).
    *
+   * @param factory the factory for {@link ByteString} instances.
    * @param numBytes the number of bytes in the byte array
    * @param expectedCount the expected number of roundtrippable permutations
    * @param start the starting bytes encoded as a long as big-endian
    * @param lim the limit of bytes to process encoded as a long as big-endian,
    *     or -1 to mean the max limit for numBytes
    */
-  void testBytesUsingByteBuffers(
-      int numBytes, long expectedCount, long start, long lim)
-      throws UnsupportedEncodingException {
-    CharsetDecoder decoder = Internal.UTF_8.newDecoder()
-        .onMalformedInput(CodingErrorAction.REPLACE)
-        .onUnmappableCharacter(CodingErrorAction.REPLACE);
-    CharsetEncoder encoder = Internal.UTF_8.newEncoder()
-        .onMalformedInput(CodingErrorAction.REPLACE)
-        .onUnmappableCharacter(CodingErrorAction.REPLACE);
+  static void testBytesUsingByteBuffers(
+      ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
+    CharsetDecoder decoder =
+        Internal.UTF_8.newDecoder()
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+    CharsetEncoder encoder =
+        Internal.UTF_8.newEncoder()
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
     byte[] bytes = new byte[numBytes];
     int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
-    char[] charsDecoded =
-        new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
+    char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
     int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
     byte[] bytesReencoded = new byte[maxBytes];
 
@@ -347,7 +387,7 @@
         bytes[bytes.length - i - 1] = (byte) tmpByteChar;
         tmpByteChar = tmpByteChar >> 8;
       }
-      boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8();
+      boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8();
       CoderResult result = decoder.decode(bb, cb, true);
       assertFalse(result.isError());
       result = decoder.flush(cb);
@@ -382,8 +422,7 @@
         countRoundTripped++;
       }
       if (byteChar != 0 && byteChar % 1000000 == 0) {
-        logger.info("Processed " + (byteChar / 1000000) +
-            " million characters");
+        logger.info("Processed " + (byteChar / 1000000) + " million characters");
       }
     }
     logger.info("Round tripped " + countRoundTripped + " of " + count);
@@ -394,10 +433,9 @@
     outputFailure(byteChar, bytes, after, after.length);
   }
 
-  private static void outputFailure(long byteChar, byte[] bytes, byte[] after,
-      int len) {
-    fail("Failure: (" + Long.toHexString(byteChar) + ") " +
-        toHexString(bytes) + " => " + toHexString(after, len));
+  private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) {
+    fail("Failure: (" + Long.toHexString(byteChar) + ") " + toHexString(bytes) + " => "
+        + toHexString(after, len));
   }
 
   private static String toHexString(byte[] b) {
@@ -416,5 +454,4 @@
     s.append("\"");
     return s.toString();
   }
-
 }
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 211b569..813fe6b 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -31,11 +31,9 @@
 package com.google.protobuf;
 
 import static protobuf_unittest.UnittestProto.optionalInt32Extension;
-import static protobuf_unittest.UnittestProto.optionalInt64Extension;
 
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-
 import java.io.IOException;
 import junit.framework.TestCase;
 
@@ -220,29 +218,6 @@
     assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
   }
 
-  public void testMergeMightLoseExtensions() throws Exception {
-    // Test that we don't know about the extensions when parsing.
-    TestAllExtensions message1 =
-        TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 1).build();
-    TestAllExtensions message2 =
-        TestAllExtensions.newBuilder().setExtension(optionalInt64Extension, 2L).build();
-
-    LazyFieldLite field = LazyFieldLite.fromValue(message1);
-    field.merge(LazyFieldLite.fromValue(message2));
-
-    // We lose the extensions from message 2 because we have to serialize it and then parse it
-    // again, using the empty registry this time.
-    TestAllExtensions value =
-        (TestAllExtensions) field.getValue(TestAllExtensions.getDefaultInstance());
-    assertTrue(value.hasExtension(optionalInt32Extension));
-    assertEquals(Integer.valueOf(1), value.getExtension(optionalInt32Extension));
-    assertFalse(value.hasExtension(optionalInt64Extension));
-
-    // The field is still there, it is just unknown.
-    assertTrue(value.getUnknownFields()
-        .hasField(optionalInt64Extension.getDescriptor().getNumber()));
-  }
-
 
   // Help methods.
 
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 2b90006..f27e8e5 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -32,8 +32,6 @@
 
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
-
-import java.io.IOException;
 import junit.framework.TestCase;
 
 /**
@@ -90,6 +88,7 @@
     assertFalse(message.equals(lazyField.getValue()));
   }
 
+  @SuppressWarnings("EqualsIncompatibleType") // LazyField.equals() is not symmetric
   public void testEqualsObjectEx() throws Exception {
     TestAllExtensions message = TestUtil.getAllExtensionsSet();
     LazyField lazyField = createLazyFieldFromMessage(message);
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 afe0fff..968ca20 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -34,10 +34,8 @@
 import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
-
-import junit.framework.TestCase;
-
 import java.util.ArrayList;
+import junit.framework.TestCase;
 
 /**
  * Unit test for messages with lazy fields.
@@ -103,6 +101,19 @@
     assertEquals(119, outer.getRepeatedInner(0).getNum());
     assertEquals(122, outer.getRepeatedInner(1).getNum());
   }
+  
+  public void testRepeatedMutability() throws Exception {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .build();
+    
+    outer = LazyMessageLite.parseFrom(outer.toByteArray());
+    try {
+      outer.getRepeatedInnerList().set(1, null);
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
 
   public void testAddAll() {
     ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
@@ -251,6 +262,23 @@
     assertEquals(42, merged.getOneofInner().getNumWithDefault());
   }
 
+  // Regression test for b/28198805.
+  public void testMergeOneofMessages() throws Exception {
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder().setOneofInner(inner).build();
+    ByteString data1 = outer.toByteString();
+
+    // The following should not alter the content of the 'outer' message.
+    LazyMessageLite.Builder merged = LazyMessageLite.newBuilder().mergeFrom(outer);
+    LazyInnerMessageLite anotherInner = LazyInnerMessageLite.newBuilder().setNum(12345).build();
+    merged.setOneofInner(anotherInner);
+
+    // Check that the 'outer' stays the same.
+    ByteString data2 = outer.toByteString();
+    assertEquals(data1, data2);
+    assertEquals(0, outer.getOneofInner().getNum());
+  }
+
   public void testSerialize() throws InvalidProtocolBufferException {
     LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
         .setNum(3)
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 0f42ac5..2fc3124 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -32,12 +32,12 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link LazyStringArrayList}.
@@ -233,7 +233,7 @@
     }
     
     try {
-      list.addAllByteArray(asList(BYTE_STRING_A.toByteArray()));
+      list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray()));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -281,6 +281,7 @@
     assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
   }
   
+  @SuppressWarnings("unchecked")
   private static <T> void assertGenericListImmutable(List<T> list, T value) {
     try {
       list.add(value);
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 0ef414a..006e493 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
@@ -32,10 +32,8 @@
 
 
 import protobuf_unittest.UnittestProto;
-
-import junit.framework.TestCase;
-
 import java.io.IOException;
+import junit.framework.TestCase;
 
 /**
  * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
diff --git a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
index 035917c..4764ca1 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
@@ -33,6 +33,8 @@
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
 
 import junit.framework.TestCase;
 
@@ -53,7 +55,7 @@
     // correctly when linked only against the lite library.
 
     // We do however do some basic testing to make sure that equals is actually
-    // overriden to test for value equality rather than simple object equality.
+    // overridden to test for value equality rather than simple object equality.
 
     // Check that two identical objs are equal.
     Foo foo1a = Foo.newBuilder()
@@ -83,6 +85,16 @@
     assertFalse(bar.equals(barPrime));
   }
 
+  public void testOneofEquals() throws Exception {
+    TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+    TestOneofEquals message1 = builder.build();
+    // Set message2's name field to default value. The two messages should be different when we
+    // check with the oneof case.
+    builder.setName("");
+    TestOneofEquals message2 = builder.build();
+    assertFalse(message1.equals(message2));
+  }
+
   public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
     Foo fooWithOnlyValue = Foo.newBuilder()
         .setValue(1)
@@ -105,4 +117,9 @@
     assertFalse(o1.equals(o2));
     assertFalse(o1.hashCode() == o2.hashCode());
   }
+
+  public void testRecursiveHashcode() {
+    // This tests that we don't infinite loop.
+    TestRecursiveOneof.getDefaultInstance().hashCode();
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index b1f298f..5ab80ca 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -33,24 +33,37 @@
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
 
-import com.google.protobuf.UnittestLite;
+import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
 import com.google.protobuf.UnittestLite.ForeignEnumLite;
 import com.google.protobuf.UnittestLite.ForeignMessageLite;
 import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite;
 import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
-
-import junit.framework.TestCase;
-
+import map_lite_test.MapTestProto.TestMap;
+import map_lite_test.MapTestProto.TestMap.MessageValue;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Test lite runtime.
@@ -58,6 +71,7 @@
  * @author kenton@google.com Kenton Varda
  */
 public class LiteTest extends TestCase {
+  @Override
   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
@@ -78,12 +92,11 @@
     // stuff to make sure the lite message is actually here and usable.
 
     TestAllTypesLite message =
-      TestAllTypesLite.newBuilder()
-                      .setOptionalInt32(123)
-                      .addRepeatedString("hello")
-                      .setOptionalNestedMessage(
-                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
-                      .build();
+        TestAllTypesLite.newBuilder()
+            .setOptionalInt32(123)
+            .addRepeatedString("hello")
+            .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+            .build();
 
     ByteString data = message.toByteString();
 
@@ -95,90 +108,97 @@
     assertEquals(7, message2.getOptionalNestedMessage().getBb());
   }
 
+  public void testLite_unknownEnumAtListBoundary() throws Exception {
+    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteStream);
+    for (int i = 0; i < AbstractProtobufList.DEFAULT_CAPACITY; i++) {
+      output.writeInt32(TestAllTypesLite.REPEATED_NESTED_ENUM_FIELD_NUMBER, 1);
+    }
+    // 0 is not a valid enum value for NestedEnum
+    output.writeInt32(TestAllTypesLite.REPEATED_NESTED_ENUM_FIELD_NUMBER, 0);
+    output.flush();
+    // This tests a bug we had once with removal right at the boundary of the array. It would throw
+    // at runtime so no need to assert.
+    TestAllTypesLite.parseFrom(new ByteArrayInputStream(byteStream.toByteArray()));
+  }
+
   public void testLiteExtensions() throws Exception {
     // TODO(kenton):  Unlike other features of the lite library, extensions are
     //   implemented completely differently from the regular library.  We
     //   should probably test them more thoroughly.
 
     TestAllExtensionsLite message =
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
-        .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
-        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
-            TestAllTypesLite.NestedEnum.BAZ)
-        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
-            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
-        .build();
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+            .setExtension(
+                UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+            .setExtension(
+                UnittestLite.optionalNestedMessageExtensionLite,
+                TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+            .build();
 
     // Test copying a message, since coping extensions actually does use a
     // different code path between lite and regular libraries, and as of this
     // 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(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
-        UnittestLite.optionalNestedEnumExtensionLite));
-    assertEquals(7, message2.getExtension(
-        UnittestLite.optionalNestedMessageExtensionLite).getBb());
+    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(
+        TestAllTypesLite.NestedEnum.BAZ,
+        message2.getExtension(UnittestLite.optionalNestedEnumExtensionLite));
+    assertEquals(7, message2.getExtension(UnittestLite.optionalNestedMessageExtensionLite).getBb());
   }
 
-  public void testSerialize() throws Exception {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    TestAllTypesLite expected =
-      TestAllTypesLite.newBuilder()
-                      .setOptionalInt32(123)
-                      .addRepeatedString("hello")
-                      .setOptionalNestedMessage(
-                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
-                      .build();
-    ObjectOutputStream out = new ObjectOutputStream(baos);
-    try {
-      out.writeObject(expected);
-    } finally {
-      out.close();
-    }
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    ObjectInputStream in = new ObjectInputStream(bais);
-    TestAllTypesLite actual = (TestAllTypesLite) in.readObject();
-    assertEquals(expected.getOptionalInt32(), actual.getOptionalInt32());
-    assertEquals(expected.getRepeatedStringCount(),
-        actual.getRepeatedStringCount());
-    assertEquals(expected.getRepeatedString(0),
-        actual.getRepeatedString(0));
-    assertEquals(expected.getOptionalNestedMessage().getBb(),
-        actual.getOptionalNestedMessage().getBb());
-  }
-  
   public void testClone() {
-    TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
-        .setOptionalInt32(123);
-    assertEquals(
-        expected.getOptionalInt32(), expected.clone().getOptionalInt32());
-   
-    TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
+    TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder().setOptionalInt32(123);
+    assertEquals(expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+
+    TestAllExtensionsLite.Builder expected2 =
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
     assertEquals(
         expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
         expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
   }
-  
+
   public void testAddAll() {
     try {
-      TestAllTypesLite.newBuilder()
-          .addAllRepeatedBytes(null);
+      TestAllTypesLite.newBuilder().addAllRepeatedBytes(null);
       fail();
     } catch (NullPointerException e) {
       // expected.
     }
   }
-  
+
+  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);
+
+    // Test hashCode is memoized
+    assertEquals(0, message.memoizedHashCode);
+    int hashCode = message.hashCode();
+    assertTrue(hashCode != 0);
+    assertEquals(hashCode, 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);
+    // We have to cast to Byte first. Casting to byte causes a type error
+    assertEquals(1, ((Byte) memo.get(message)).intValue());
+  }
+
   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
@@ -202,13 +222,11 @@
     assertEquals(ByteString.EMPTY, message.getOptionalBytes());
     assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes());
     messageAfterBuild = builder.build();
-    assertEquals(
-        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
     assertEquals(ByteString.EMPTY, message.getOptionalBytes());
     builder.clearOptionalBytes();
     assertEquals(ByteString.EMPTY, builder.getOptionalBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
 
     message = builder.build();
     builder.setOptionalCord("hi");
@@ -226,27 +244,23 @@
     assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
     assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes());
     messageAfterBuild = builder.build();
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalCordBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
     assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
     builder.clearOptionalCord();
     assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalCordBytes());
-    
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalCordBytes());
+
     message = builder.build();
     builder.setOptionalDouble(1);
-    assertEquals(0D, message.getOptionalDouble());
-    assertEquals(1D, builder.getOptionalDouble());
+    assertEquals(0D, message.getOptionalDouble(), 0.0);
+    assertEquals(1D, builder.getOptionalDouble(), 0.0);
     messageAfterBuild = builder.build();
-    assertEquals(1D, messageAfterBuild.getOptionalDouble());
-    assertEquals(0D, message.getOptionalDouble());
+    assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
+    assertEquals(0D, message.getOptionalDouble(), 0.0);
     builder.clearOptionalDouble();
-    assertEquals(0D, builder.getOptionalDouble());
-    assertEquals(1D, messageAfterBuild.getOptionalDouble());
-    
+    assertEquals(0D, builder.getOptionalDouble(), 0.0);
+    assertEquals(1D, messageAfterBuild.getOptionalDouble(), 0.0);
+
     message = builder.build();
     builder.setOptionalFixed32(1);
     assertEquals(0, message.getOptionalFixed32());
@@ -257,7 +271,7 @@
     builder.clearOptionalFixed32();
     assertEquals(0, builder.getOptionalFixed32());
     assertEquals(1, messageAfterBuild.getOptionalFixed32());
-    
+
     message = builder.build();
     builder.setOptionalFixed64(1);
     assertEquals(0L, message.getOptionalFixed64());
@@ -271,110 +285,73 @@
 
     message = builder.build();
     builder.setOptionalFloat(1);
-    assertEquals(0F, message.getOptionalFloat());
-    assertEquals(1F, builder.getOptionalFloat());
+    assertEquals(0F, message.getOptionalFloat(), 0.0f);
+    assertEquals(1F, builder.getOptionalFloat(), 0.0f);
     messageAfterBuild = builder.build();
-    assertEquals(1F, messageAfterBuild.getOptionalFloat());
-    assertEquals(0F, message.getOptionalFloat());
+    assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
+    assertEquals(0F, message.getOptionalFloat(), 0.0f);
     builder.clearOptionalFloat();
-    assertEquals(0F, builder.getOptionalFloat());
-    assertEquals(1F, messageAfterBuild.getOptionalFloat());
+    assertEquals(0F, builder.getOptionalFloat(), 0.0f);
+    assertEquals(1F, messageAfterBuild.getOptionalFloat(), 0.0f);
 
     message = builder.build();
     builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
     messageAfterBuild = builder.build();
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_BAR,
-        messageAfterBuild.getOptionalForeignEnum());
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
     builder.clearOptionalForeignEnum();
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_BAR,
-        messageAfterBuild.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getOptionalForeignEnum());
 
     message = builder.build();
-    ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder()
-        .setC(1)
-        .build();
+    ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder().setC(1).build();
     builder.setOptionalForeignMessage(foreignMessage);
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        message.getOptionalForeignMessage());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
     assertEquals(foreignMessage, builder.getOptionalForeignMessage());
     messageAfterBuild = builder.build();
     assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        message.getOptionalForeignMessage());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
     builder.clearOptionalForeignMessage();
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        builder.getOptionalForeignMessage());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
     assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
 
     message = builder.build();
-    ForeignMessageLite.Builder foreignMessageBuilder =
-        ForeignMessageLite.newBuilder()
-            .setC(3);
+    ForeignMessageLite.Builder foreignMessageBuilder = ForeignMessageLite.newBuilder().setC(3);
     builder.setOptionalForeignMessage(foreignMessageBuilder);
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        message.getOptionalForeignMessage());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on foreignMessage.
-    assertEquals(3, builder.getOptionalForeignMessage().getC());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
+    assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
     messageAfterBuild = builder.build();
-    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        message.getOptionalForeignMessage());
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
     builder.clearOptionalForeignMessage();
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        builder.getOptionalForeignMessage());
-    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
 
     message = builder.build();
-    OptionalGroup optionalGroup = OptionalGroup.newBuilder()
-        .setA(1)
-        .build();
+    OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
     builder.setOptionalGroup(optionalGroup);
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
     assertEquals(optionalGroup, builder.getOptionalGroup());
     messageAfterBuild = builder.build();
     assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
     builder.clearOptionalGroup();
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
     assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
 
     message = builder.build();
-    OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder()
-        .setA(3);
+    OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder().setA(3);
     builder.setOptionalGroup(optionalGroupBuilder);
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on optionalGroup.
-    assertEquals(3, builder.getOptionalGroup().getA());
+    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup());
     messageAfterBuild = builder.build();
-    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
+    assertEquals(OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
     builder.clearOptionalGroup();
-    assertEquals(
-        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
-    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+    assertEquals(OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
 
     message = builder.build();
     builder.setOptionalInt32(1);
@@ -397,45 +374,30 @@
     builder.clearOptionalInt64();
     assertEquals(0L, builder.getOptionalInt64());
     assertEquals(1L, messageAfterBuild.getOptionalInt64());
-    
+
     message = builder.build();
-    NestedMessage nestedMessage = NestedMessage.newBuilder()
-        .setBb(1)
-        .build();
+    NestedMessage nestedMessage = NestedMessage.newBuilder().setBb(1).build();
     builder.setOptionalLazyMessage(nestedMessage);
-    assertEquals(
-        NestedMessage.getDefaultInstance(),
-        message.getOptionalLazyMessage());
+    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
     assertEquals(nestedMessage, builder.getOptionalLazyMessage());
     messageAfterBuild = builder.build();
     assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
-    assertEquals(
-        NestedMessage.getDefaultInstance(),
-        message.getOptionalLazyMessage());
+    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
     builder.clearOptionalLazyMessage();
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
     assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
 
     message = builder.build();
-    NestedMessage.Builder nestedMessageBuilder =
-        NestedMessage.newBuilder()
-            .setBb(3);
+    NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(3);
     builder.setOptionalLazyMessage(nestedMessageBuilder);
-    assertEquals(
-        NestedMessage.getDefaultInstance(),
-        message.getOptionalLazyMessage());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property.
-    assertEquals(3, builder.getOptionalLazyMessage().getBb());
+    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
+    assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage());
     messageAfterBuild = builder.build();
-    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
-    assertEquals(
-        NestedMessage.getDefaultInstance(),
-        message.getOptionalLazyMessage());
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
+    assertEquals(NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage());
     builder.clearOptionalLazyMessage();
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
-    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
 
     message = builder.build();
     builder.setOptionalSfixed32(1);
@@ -494,19 +456,14 @@
     message = builder.build();
     builder.setOptionalStringBytes(ByteString.copyFromUtf8("no"));
     assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
     messageAfterBuild = builder.build();
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalStringBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
     assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
     builder.clearOptionalString();
     assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalStringBytes());
-    
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringBytes());
+
     message = builder.build();
     builder.setOptionalStringPiece("hi");
     assertEquals("", message.getOptionalStringPiece());
@@ -521,18 +478,13 @@
     message = builder.build();
     builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no"));
     assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
     messageAfterBuild = builder.build();
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalStringPieceBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
     assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
     builder.clearOptionalStringPiece();
     assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes());
-    assertEquals(
-        ByteString.copyFromUtf8("no"),
-        messageAfterBuild.getOptionalStringPieceBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), messageAfterBuild.getOptionalStringPieceBytes());
 
     message = builder.build();
     builder.setOptionalUint32(1);
@@ -569,16 +521,13 @@
     message = builder.build();
     builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi")));
     assertEquals(emptyList(), message.getRepeatedBytesList());
-    assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")),
-        builder.getRepeatedBytesList());
+    assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
     assertEquals(emptyList(), message.getRepeatedBytesList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedBytes();
     assertEquals(emptyList(), builder.getRepeatedBytesList());
     assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")),
-        messageAfterBuild.getRepeatedBytesList());
+        singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
 
     message = builder.build();
     builder.addAllRepeatedCord(singletonList("hi"));
@@ -631,12 +580,10 @@
     assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
 
     message = builder.build();
-    builder.addAllRepeatedForeignEnum(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
+    builder.addAllRepeatedForeignEnum(singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
     assertEquals(emptyList(), message.getRepeatedForeignEnumList());
     assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
-        builder.getRepeatedForeignEnumList());
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
     assertEquals(emptyList(), message.getRepeatedForeignEnumList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignEnum();
@@ -648,23 +595,17 @@
     message = builder.build();
     builder.addAllRepeatedForeignMessage(singletonList(foreignMessage));
     assertEquals(emptyList(), message.getRepeatedForeignMessageList());
-    assertEquals(
-        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
     assertEquals(emptyList(), message.getRepeatedForeignMessageList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignMessage();
     assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
-    assertEquals(
-        singletonList(foreignMessage),
-        messageAfterBuild.getRepeatedForeignMessageList());
+    assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
 
     message = builder.build();
-    builder.addAllRepeatedGroup(
-        singletonList(RepeatedGroup.getDefaultInstance()));
+    builder.addAllRepeatedGroup(singletonList(RepeatedGroup.getDefaultInstance()));
     assertEquals(emptyList(), message.getRepeatedGroupList());
-    assertEquals(
-        singletonList(RepeatedGroup.getDefaultInstance()),
-        builder.getRepeatedGroupList());
+    assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
     assertEquals(emptyList(), message.getRepeatedGroupList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedGroup();
@@ -696,15 +637,12 @@
     message = builder.build();
     builder.addAllRepeatedLazyMessage(singletonList(nestedMessage));
     assertEquals(emptyList(), message.getRepeatedLazyMessageList());
-    assertEquals(
-        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
     assertEquals(emptyList(), message.getRepeatedLazyMessageList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedLazyMessage();
     assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
-    assertEquals(
-        singletonList(nestedMessage),
-        messageAfterBuild.getRepeatedLazyMessageList());
+    assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
 
     message = builder.build();
     builder.addAllRepeatedSfixed32(singletonList(1));
@@ -724,8 +662,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed64();
     assertEquals(emptyList(), builder.getRepeatedSfixed64List());
-    assertEquals(
-        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
 
     message = builder.build();
     builder.addAllRepeatedSint32(singletonList(1));
@@ -755,8 +692,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedString();
     assertEquals(emptyList(), builder.getRepeatedStringList());
-    assertEquals(
-        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
 
     message = builder.build();
     builder.addAllRepeatedStringPiece(singletonList("hi"));
@@ -766,8 +702,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedStringPiece();
     assertEquals(emptyList(), builder.getRepeatedStringPieceList());
-    assertEquals(
-        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
 
     message = builder.build();
     builder.addAllRepeatedUint32(singletonList(1));
@@ -802,16 +737,13 @@
     message = builder.build();
     builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
     assertEquals(emptyList(), message.getRepeatedBytesList());
-    assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")),
-        builder.getRepeatedBytesList());
+    assertEquals(singletonList(ByteString.copyFromUtf8("hi")), builder.getRepeatedBytesList());
     assertEquals(emptyList(), message.getRepeatedBytesList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedBytes();
     assertEquals(emptyList(), builder.getRepeatedBytesList());
     assertEquals(
-        singletonList(ByteString.copyFromUtf8("hi")),
-        messageAfterBuild.getRepeatedBytesList());
+        singletonList(ByteString.copyFromUtf8("hi")), messageAfterBuild.getRepeatedBytesList());
 
     message = builder.build();
     builder.addRepeatedCord("hi");
@@ -867,8 +799,7 @@
     builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
     assertEquals(emptyList(), message.getRepeatedForeignEnumList());
     assertEquals(
-        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
-        builder.getRepeatedForeignEnumList());
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), builder.getRepeatedForeignEnumList());
     assertEquals(emptyList(), message.getRepeatedForeignEnumList());
     messageAfterBuild = builder.build();
     builder.clearRepeatedForeignEnum();
@@ -880,22 +811,17 @@
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessage);
     assertEquals(emptyList(), message.getRepeatedForeignMessageList());
-    assertEquals(
-        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
     assertEquals(emptyList(), message.getRepeatedForeignMessageList());
     messageAfterBuild = builder.build();
     builder.removeRepeatedForeignMessage(0);
     assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
-    assertEquals(
-        singletonList(foreignMessage),
-        messageAfterBuild.getRepeatedForeignMessageList());
+    assertEquals(singletonList(foreignMessage), messageAfterBuild.getRepeatedForeignMessageList());
 
     message = builder.build();
     builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance());
     assertEquals(emptyList(), message.getRepeatedGroupList());
-    assertEquals(
-        singletonList(RepeatedGroup.getDefaultInstance()),
-        builder.getRepeatedGroupList());
+    assertEquals(singletonList(RepeatedGroup.getDefaultInstance()), builder.getRepeatedGroupList());
     assertEquals(emptyList(), message.getRepeatedGroupList());
     messageAfterBuild = builder.build();
     builder.removeRepeatedGroup(0);
@@ -927,15 +853,12 @@
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessage);
     assertEquals(emptyList(), message.getRepeatedLazyMessageList());
-    assertEquals(
-        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
     assertEquals(emptyList(), message.getRepeatedLazyMessageList());
     messageAfterBuild = builder.build();
     builder.removeRepeatedLazyMessage(0);
     assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
-    assertEquals(
-        singletonList(nestedMessage),
-        messageAfterBuild.getRepeatedLazyMessageList());
+    assertEquals(singletonList(nestedMessage), messageAfterBuild.getRepeatedLazyMessageList());
 
     message = builder.build();
     builder.addRepeatedSfixed32(1);
@@ -955,8 +878,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedSfixed64();
     assertEquals(emptyList(), builder.getRepeatedSfixed64List());
-    assertEquals(
-        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
 
     message = builder.build();
     builder.addRepeatedSint32(1);
@@ -986,8 +908,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedString();
     assertEquals(emptyList(), builder.getRepeatedStringList());
-    assertEquals(
-        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringList());
 
     message = builder.build();
     builder.addRepeatedStringPiece("hi");
@@ -997,8 +918,7 @@
     messageAfterBuild = builder.build();
     builder.clearRepeatedStringPiece();
     assertEquals(emptyList(), builder.getRepeatedStringPieceList());
-    assertEquals(
-        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
 
     message = builder.build();
     builder.addRepeatedUint32(1);
@@ -1019,7 +939,7 @@
     builder.clearRepeatedUint64();
     assertEquals(emptyList(), builder.getRepeatedUint64List());
     assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
-    
+
     message = builder.build();
     builder.addRepeatedBool(true);
     messageAfterBuild = builder.build();
@@ -1028,14 +948,13 @@
     assertEquals(true, messageAfterBuild.getRepeatedBool(0));
     assertEquals(false, builder.getRepeatedBool(0));
     builder.clearRepeatedBool();
-    
+
     message = builder.build();
     builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedBytesCount());
     builder.setRepeatedBytes(0, ByteString.EMPTY);
-    assertEquals(
-        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
     assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0));
     builder.clearRepeatedBytes();
 
@@ -1053,8 +972,7 @@
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedCordCount());
     builder.setRepeatedCord(0, "");
-    assertEquals(
-        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
     assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0));
     builder.clearRepeatedCord();
 
@@ -1063,8 +981,8 @@
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedDoubleCount());
     builder.setRepeatedDouble(0, 0D);
-    assertEquals(1D, messageAfterBuild.getRepeatedDouble(0));
-    assertEquals(0D, builder.getRepeatedDouble(0));
+    assertEquals(1D, messageAfterBuild.getRepeatedDouble(0), 0.0);
+    assertEquals(0D, builder.getRepeatedDouble(0), 0.0);
     builder.clearRepeatedDouble();
 
     message = builder.build();
@@ -1090,8 +1008,8 @@
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedFloatCount());
     builder.setRepeatedFloat(0, 0F);
-    assertEquals(1F, messageAfterBuild.getRepeatedFloat(0));
-    assertEquals(0F, builder.getRepeatedFloat(0));
+    assertEquals(1F, messageAfterBuild.getRepeatedFloat(0), 0.0f);
+    assertEquals(0F, builder.getRepeatedFloat(0), 0.0f);
     builder.clearRepeatedFloat();
 
     message = builder.build();
@@ -1099,37 +1017,26 @@
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignEnumCount());
     builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO);
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_BAR,
-        messageAfterBuild.getRepeatedForeignEnum(0));
-    assertEquals(
-        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, messageAfterBuild.getRepeatedForeignEnum(0));
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
     builder.clearRepeatedForeignEnum();
 
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessage);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignMessageCount());
-    builder.setRepeatedForeignMessage(
-        0, ForeignMessageLite.getDefaultInstance());
-    assertEquals(
-        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        builder.getRepeatedForeignMessage(0));
+    builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
+    assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
     builder.clearRepeatedForeignMessage();
-    
+
     message = builder.build();
     builder.addRepeatedForeignMessage(foreignMessageBuilder);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignMessageCount());
-    builder.setRepeatedForeignMessage(
-        0, ForeignMessageLite.getDefaultInstance());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property.
-    assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC());
-    assertEquals(
-        ForeignMessageLite.getDefaultInstance(),
-        builder.getRepeatedForeignMessage(0));
+    builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
@@ -1137,59 +1044,46 @@
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignMessageCount());
     builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
-    assertEquals(
-        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
-    // LITE_RUNTIME doesn't implement equals so we compare on a property.
-    assertEquals(3, builder.getRepeatedForeignMessage(0).getC());
+    assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
-    RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder()
-        .setA(1)
-        .build();
+    RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder().setA(1).build();
     builder.addRepeatedGroup(repeatedGroup);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedGroupCount());
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
     assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(
-        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
     builder.clearRepeatedGroup();
-    
+
     message = builder.build();
     builder.addRepeatedGroup(0, repeatedGroup);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedGroupCount());
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
     assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
-    assertEquals(
-        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
     builder.clearRepeatedGroup();
-    
+
     message = builder.build();
-    RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder()
-        .setA(3);
+    RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder().setA(3);
     builder.addRepeatedGroup(repeatedGroupBuilder);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedGroupCount());
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on repeatedGroup.
-    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
-    assertEquals(
-        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
     builder.clearRepeatedGroup();
-    
+
     message = builder.build();
     builder.addRepeatedGroup(0, repeatedGroupBuilder);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedGroupCount());
     builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on repeatedGroup.
-    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
-    assertEquals(
-        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
     builder.clearRepeatedGroup();
 
     message = builder.build();
@@ -1209,49 +1103,41 @@
     assertEquals(1L, messageAfterBuild.getRepeatedInt64(0));
     assertEquals(0L, builder.getRepeatedInt64(0));
     builder.clearRepeatedInt64();
-    
+
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessage);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedLazyMessageCount());
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
     assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
     builder.clearRepeatedLazyMessage();
-    
+
     message = builder.build();
     builder.addRepeatedLazyMessage(0, nestedMessage);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedLazyMessageCount());
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
     assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
     builder.clearRepeatedLazyMessage();
-    
+
     message = builder.build();
     builder.addRepeatedLazyMessage(nestedMessageBuilder);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedLazyMessageCount());
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on repeatedGroup.
-    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
     builder.clearRepeatedLazyMessage();
-    
+
     message = builder.build();
     builder.addRepeatedLazyMessage(0, nestedMessageBuilder);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedLazyMessageCount());
     builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
-    // LITE_RUNTIME doesn't implement equals so we compare on a property and
-    // ensure the property isn't set on repeatedGroup.
-    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
-    assertEquals(
-        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
     builder.clearRepeatedLazyMessage();
 
     message = builder.build();
@@ -1304,9 +1190,7 @@
     messageAfterBuild = builder.build();
     assertEquals(0L, message.getRepeatedStringCount());
     builder.setRepeatedString(0, "");
-    assertEquals(
-        ByteString.copyFromUtf8("hi"),
-        messageAfterBuild.getRepeatedStringBytes(0));
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringBytes(0));
     assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0));
     builder.clearRepeatedString();
 
@@ -1324,9 +1208,7 @@
     messageAfterBuild = builder.build();
     assertEquals(0L, message.getRepeatedStringPieceCount());
     builder.setRepeatedStringPiece(0, "");
-    assertEquals(
-        ByteString.copyFromUtf8("hi"),
-        messageAfterBuild.getRepeatedStringPieceBytes(0));
+    assertEquals(ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedStringPieceBytes(0));
     assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0));
     builder.clearRepeatedStringPiece();
 
@@ -1350,18 +1232,14 @@
 
     message = builder.build();
     assertEquals(0, message.getSerializedSize());
-    builder.mergeFrom(TestAllTypesLite.newBuilder()
-        .setOptionalBool(true)
-        .build());
+    builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
     assertEquals(0, message.getSerializedSize());
     assertEquals(true, builder.build().getOptionalBool());
     builder.clearOptionalBool();
 
     message = builder.build();
     assertEquals(0, message.getSerializedSize());
-    builder.mergeFrom(TestAllTypesLite.newBuilder()
-        .setOptionalBool(true)
-        .build());
+    builder.mergeFrom(TestAllTypesLite.newBuilder().setOptionalBool(true).build());
     assertEquals(0, message.getSerializedSize());
     assertEquals(true, builder.build().getOptionalBool());
     builder.clear();
@@ -1371,92 +1249,1133 @@
     assertEquals(0, message.getSerializedSize());
     builder.mergeOptionalForeignMessage(foreignMessage);
     assertEquals(0, message.getSerializedSize());
-    assertEquals(
-        foreignMessage.getC(),
-        builder.build().getOptionalForeignMessage().getC());
+    assertEquals(foreignMessage.getC(), builder.build().getOptionalForeignMessage().getC());
     builder.clearOptionalForeignMessage();
 
     message = builder.build();
     assertEquals(0, message.getSerializedSize());
     builder.mergeOptionalLazyMessage(nestedMessage);
     assertEquals(0, message.getSerializedSize());
-    assertEquals(
-        nestedMessage.getBb(),
-        builder.build().getOptionalLazyMessage().getBb());
+    assertEquals(nestedMessage.getBb(), builder.build().getOptionalLazyMessage().getBb());
     builder.clearOptionalLazyMessage();
-    
+
     message = builder.build();
     builder.setOneofString("hi");
-    assertEquals(
-        OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
+    assertEquals(OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
     assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase());
     assertEquals("hi", builder.getOneofString());
     messageAfterBuild = builder.build();
-    assertEquals(
-        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
     assertEquals("hi", messageAfterBuild.getOneofString());
     builder.setOneofUint32(1);
-    assertEquals(
-        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals(OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
     assertEquals("hi", messageAfterBuild.getOneofString());
     assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
     assertEquals(1, builder.getOneofUint32());
     TestAllTypesLiteOrBuilder messageOrBuilder = builder;
     assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase());
-    
-    TestAllExtensionsLite.Builder extendableMessageBuilder =
-        TestAllExtensionsLite.newBuilder();
+
+    TestAllExtensionsLite.Builder extendableMessageBuilder = TestAllExtensionsLite.newBuilder();
     TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build();
-    extendableMessageBuilder.setExtension(
-        UnittestLite.optionalInt32ExtensionLite, 1);
-    assertFalse(extendableMessage.hasExtension(
-        UnittestLite.optionalInt32ExtensionLite));
+    extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 1);
+    assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
     extendableMessage = extendableMessageBuilder.build();
     assertEquals(
-        1, (int) extendableMessageBuilder.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
+        1, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    extendableMessageBuilder.setExtension(UnittestLite.optionalInt32ExtensionLite, 3);
     assertEquals(
-        1, (int) extendableMessage.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
-    extendableMessageBuilder.setExtension(
-        UnittestLite.optionalInt32ExtensionLite, 3);
-    assertEquals(
-        3, (int) extendableMessageBuilder.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(
-        1, (int) extendableMessage.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
+        3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(1, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
     extendableMessage = extendableMessageBuilder.build();
     assertEquals(
-        3, (int) extendableMessageBuilder.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(
-        3, (int) extendableMessage.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
-    
+        3, (int) extendableMessageBuilder.getExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
+
     // No extension registry, so it should be in unknown fields.
-    extendableMessage =
-        TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
-    assertFalse(extendableMessage.hasExtension(
-        UnittestLite.optionalInt32ExtensionLite));
-    
+    extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
+    assertFalse(extendableMessage.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+
     extendableMessageBuilder = extendableMessage.toBuilder();
-    extendableMessageBuilder.mergeFrom(TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
-        .build());
-    
+    extendableMessageBuilder.mergeFrom(
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
+            .build());
+
     extendableMessage = extendableMessageBuilder.build();
     ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
     UnittestLite.registerAllExtensions(registry);
-    extendableMessage = TestAllExtensionsLite.parseFrom(
-        extendableMessage.toByteArray(), registry);
-    
+    extendableMessage = TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray(), registry);
+
     // The unknown field was preserved.
+    assertEquals(3, (int) extendableMessage.getExtension(UnittestLite.optionalInt32ExtensionLite));
     assertEquals(
-        3, (int) extendableMessage.getExtension(
-            UnittestLite.optionalInt32ExtensionLite));
+        11, (int) extendableMessage.getExtension(UnittestLite.optionalFixed32ExtensionLite));
+  }
+
+  public void testBuilderMergeFromNull() throws Exception {
+    try {
+      TestAllTypesLite.newBuilder().mergeFrom((TestAllTypesLite) null);
+      fail("Expected exception");
+    } catch (NullPointerException e) {
+      // Pass.
+    }
+  }
+
+  // Builder.mergeFrom() should keep existing extensions.
+  public void testBuilderMergeFromWithExtensions() throws Exception {
+    TestAllExtensionsLite message =
+        TestAllExtensionsLite.newBuilder()
+            .addExtension(UnittestLite.repeatedInt32ExtensionLite, 12)
+            .build();
+
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    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());
+  }
+
+  // Builder.mergeFrom() should keep existing unknown fields.
+  public void testBuilderMergeFromWithUnknownFields() throws Exception {
+    TestAllTypesLite message = TestAllTypesLite.newBuilder().addRepeatedInt32(1).build();
+
+    NestedMessage.Builder builder = NestedMessage.newBuilder();
+    builder.mergeFrom(message.toByteArray());
+    builder.mergeFrom(message.toByteArray());
+    NestedMessage result = builder.build();
+    assertEquals(message.getSerializedSize() * 2, result.getSerializedSize());
+  }
+
+  public void testToStringDefaultInstance() throws Exception {
+    assertToStringEquals("", TestAllTypesLite.getDefaultInstance());
+  }
+
+  public void testToStringScalarFieldsSuffixedWithList() throws Exception {
+    assertToStringEquals(
+        "deceptively_named_list: 7",
+        TestAllTypesLite.newBuilder().setDeceptivelyNamedList(7).build());
+  }
+
+  public void testToStringPrimitives() throws Exception {
+    TestAllTypesLite proto =
+        TestAllTypesLite.newBuilder()
+            .setOptionalInt32(1)
+            .setOptionalInt64(9223372036854775807L)
+            .build();
+    assertToStringEquals("optional_int32: 1\noptional_int64: 9223372036854775807", proto);
+
+    proto =
+        TestAllTypesLite.newBuilder()
+            .setOptionalBool(true)
+            .setOptionalNestedEnum(TestAllTypesLite.NestedEnum.BAZ)
+            .build();
+    assertToStringEquals("optional_bool: true\noptional_nested_enum: BAZ", proto);
+
+    proto = TestAllTypesLite.newBuilder().setOptionalFloat(2.72f).setOptionalDouble(3.14).build();
+    assertToStringEquals("optional_double: 3.14\noptional_float: 2.72", proto);
+  }
+
+  public void testToStringStringFields() throws Exception {
+    TestAllTypesLite proto =
+        TestAllTypesLite.newBuilder().setOptionalString("foo\"bar\nbaz\\").build();
+    assertToStringEquals("optional_string: \"foo\\\"bar\\nbaz\\\\\"", proto);
+
+    proto = TestAllTypesLite.newBuilder().setOptionalString("\u6587").build();
+    assertToStringEquals("optional_string: \"\\346\\226\\207\"", proto);
+  }
+
+  public void testToStringNestedMessage() throws Exception {
+    TestAllTypesLite proto =
+        TestAllTypesLite.newBuilder()
+            .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.getDefaultInstance())
+            .build();
+    assertToStringEquals("optional_nested_message {\n}", proto);
+
+    proto =
+        TestAllTypesLite.newBuilder()
+            .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+            .build();
+    assertToStringEquals("optional_nested_message {\n  bb: 7\n}", proto);
+  }
+
+  public void testToStringRepeatedFields() throws Exception {
+    TestAllTypesLite proto =
+        TestAllTypesLite.newBuilder()
+            .addRepeatedInt32(32)
+            .addRepeatedInt32(32)
+            .addRepeatedInt64(64)
+            .build();
+    assertToStringEquals("repeated_int32: 32\nrepeated_int32: 32\nrepeated_int64: 64", proto);
+
+    proto =
+        TestAllTypesLite.newBuilder()
+            .addRepeatedLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+            .addRepeatedLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(8))
+            .build();
+    assertToStringEquals(
+        "repeated_lazy_message {\n  bb: 7\n}\nrepeated_lazy_message {\n  bb: 8\n}", proto);
+  }
+
+  public void testToStringForeignFields() throws Exception {
+    TestAllTypesLite proto =
+        TestAllTypesLite.newBuilder()
+            .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+            .setOptionalForeignMessage(ForeignMessageLite.newBuilder().setC(3))
+            .build();
+    assertToStringEquals(
+        "optional_foreign_enum: FOREIGN_LITE_BAR\noptional_foreign_message {\n  c: 3\n}", proto);
+  }
+
+  public void testToStringExtensions() throws Exception {
+    TestAllExtensionsLite message =
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+            .setExtension(
+                UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+            .setExtension(
+                UnittestLite.optionalNestedMessageExtensionLite,
+                TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+            .build();
+    assertToStringEquals(
+        "[1]: 123\n[18] {\n  bb: 7\n}\n[21]: 3\n[44]: \"spam\"\n[44]: \"eggs\"", message);
+  }
+
+  public void testToStringUnknownFields() throws Exception {
+    TestAllExtensionsLite messageWithExtensions =
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+            .setExtension(
+                UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+            .setExtension(
+                UnittestLite.optionalNestedMessageExtensionLite,
+                TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+            .build();
+    TestAllExtensionsLite messageWithUnknownFields =
+        TestAllExtensionsLite.parseFrom(messageWithExtensions.toByteArray());
+    assertToStringEquals(
+        "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"", messageWithUnknownFields);
+  }
+
+  public void testToStringLazyMessage() throws Exception {
+    TestAllTypesLite message =
+        TestAllTypesLite.newBuilder()
+            .setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1).build())
+            .build();
+    assertToStringEquals("optional_lazy_message {\n  bb: 1\n}", message);
+  }
+
+  public void testToStringGroup() throws Exception {
+    TestAllTypesLite message =
+        TestAllTypesLite.newBuilder()
+            .setOptionalGroup(OptionalGroup.newBuilder().setA(1).build())
+            .build();
+    assertToStringEquals("optional_group {\n  a: 1\n}", message);
+  }
+
+  public void testToStringOneof() throws Exception {
+    TestAllTypesLite message = TestAllTypesLite.newBuilder().setOneofString("hello").build();
+    assertToStringEquals("oneof_string: \"hello\"", message);
+  }
+
+  public void testToStringMapFields() throws Exception {
+    TestMap message1 =
+        TestMap.newBuilder()
+            .putInt32ToStringField(1, "alpha")
+            .putInt32ToStringField(2, "beta")
+            .build();
+    assertToStringEquals(
+        "int32_to_string_field {\n"
+            + "  key: 1\n"
+            + "  value: \"alpha\"\n"
+            + "}\n"
+            + "int32_to_string_field {\n"
+            + "  key: 2\n"
+            + "  value: \"beta\"\n"
+            + "}",
+        message1);
+
+    TestMap message2 =
+        TestMap.newBuilder()
+            .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(10).build())
+            .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(20).build())
+            .build();
+    assertToStringEquals(
+        "int32_to_message_field {\n"
+            + "  key: 1\n"
+            + "  value {\n"
+            + "    value: 10\n"
+            + "  }\n"
+            + "}\n"
+            + "int32_to_message_field {\n"
+            + "  key: 2\n"
+            + "  value {\n"
+            + "    value: 20\n"
+            + "  }\n"
+            + "}",
+        message2);
+  }
+
+  // Asserts that the toString() representation of the message matches the expected. This verifies
+  // the first line starts with a comment; but, does not factor in said comment as part of the
+  // comparison as it contains unstable addresses.
+  private static void assertToStringEquals(String expected, MessageLite message) {
+    String toString = message.toString();
+    assertEquals('#', toString.charAt(0));
+    if (toString.indexOf("\n") >= 0) {
+      toString = toString.substring(toString.indexOf("\n") + 1);
+    } else {
+      toString = "";
+    }
+    assertEquals(expected, toString);
+  }
+
+  public void testParseLazy() throws Exception {
+    ByteString bb =
+        TestAllTypesLite.newBuilder()
+            .setOptionalLazyMessage(NestedMessage.newBuilder().setBb(11).build())
+            .build()
+            .toByteString();
+    ByteString cc =
+        TestAllTypesLite.newBuilder()
+            .setOptionalLazyMessage(NestedMessage.newBuilder().setCc(22).build())
+            .build()
+            .toByteString();
+
+    ByteString concat = bb.concat(cc);
+    TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+    assertEquals(11, message.getOptionalLazyMessage().getBb());
+    assertEquals(22L, message.getOptionalLazyMessage().getCc());
+  }
+
+  public void testParseLazy_oneOf() throws Exception {
+    ByteString bb =
+        TestAllTypesLite.newBuilder()
+            .setOneofLazyNestedMessage(NestedMessage.newBuilder().setBb(11).build())
+            .build()
+            .toByteString();
+    ByteString cc =
+        TestAllTypesLite.newBuilder()
+            .setOneofLazyNestedMessage(NestedMessage.newBuilder().setCc(22).build())
+            .build()
+            .toByteString();
+
+    ByteString concat = bb.concat(cc);
+    TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+    assertEquals(11, message.getOneofLazyNestedMessage().getBb());
+    assertEquals(22L, message.getOneofLazyNestedMessage().getCc());
+  }
+
+  public void testMergeFromStream_repeatedField() throws Exception {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder().addRepeatedString("hello");
+    builder.mergeFrom(CodedInputStream.newInstance(builder.build().toByteArray()));
+
+    assertEquals(2, builder.getRepeatedStringCount());
+  }
+
+  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();
+    } catch (InvalidProtocolBufferException expected) {
+    }
+  }
+
+  public void testMergeFrom_sanity() throws Exception {
+    TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+    byte[] bytes = one.toByteArray();
+    TestAllTypesLite two = TestAllTypesLite.parseFrom(bytes);
+
+    one = one.toBuilder().mergeFrom(one).build();
+    two = two.toBuilder().mergeFrom(bytes).build();
+    assertEquals(one, two);
+    assertEquals(two, one);
+    assertEquals(one.hashCode(), two.hashCode());
+  }
+
+  public void testMergeFromNoLazyFieldSharing() throws Exception {
+    TestAllTypesLite.Builder sourceBuilder =
+        TestAllTypesLite.newBuilder()
+            .setOptionalLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(1));
+    TestAllTypesLite.Builder targetBuilder =
+        TestAllTypesLite.newBuilder().mergeFrom(sourceBuilder.build());
+    assertEquals(1, sourceBuilder.getOptionalLazyMessage().getBb());
+    // now change the sourceBuilder, and target value shouldn't be affected.
+    sourceBuilder.setOptionalLazyMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(2));
+    assertEquals(1, targetBuilder.getOptionalLazyMessage().getBb());
+  }
+
+  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));
+
+    assertFalse(one.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(one));
+
+    TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBool(true).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCord("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultCordBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultDouble(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultFloat(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().setDefaultImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultInt64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultNestedEnum(NestedEnum.BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSfixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultSint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultString("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultStringPiece("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().setDefaultStringPieceBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setDefaultUint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBool(true).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCord("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedCordBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedDouble(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedFloat(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().addRepeatedImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedInt64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedNestedEnum(NestedEnum.BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSfixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedSint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedString("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedStringPiece("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().addRepeatedStringPieceBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().addRepeatedUint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBool(true).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCord("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalCordBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalDouble(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalFloat(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().setOptionalImportEnum(ImportEnumLite.IMPORT_LITE_BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalInt64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSfixed64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalSint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalString("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalStringPiece("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().setOptionalStringPieceBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOptionalUint64(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOneofBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOneofString("").build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOneofStringBytes(ByteString.EMPTY).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder().setOneofUint32(0).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder().setOptionalGroup(OptionalGroup.getDefaultInstance()).build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    oneFieldSet =
+        TestAllTypesLite.newBuilder()
+            .addRepeatedLazyMessage(NestedMessage.getDefaultInstance())
+            .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+  }
+
+  public void testEquals() throws Exception {
+    // Check that two identical objs are equal.
+    Foo foo1a = Foo.newBuilder().setValue(1).addBar(Bar.newBuilder().setName("foo1")).build();
+    Foo foo1b = Foo.newBuilder().setValue(1).addBar(Bar.newBuilder().setName("foo1")).build();
+    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());
+
+    // Check that a diffeent object is not equal.
+    assertFalse(foo1a.equals(foo2));
+
+    // 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));
+  }
+
+  public void testEqualsAndHashCodeForTrickySchemaTypes() {
+    Foo foo1 = Foo.getDefaultInstance();
+    Foo foo2 = Foo.newBuilder().setSint64(1).build();
+    Foo foo3 = Foo.newBuilder().putMyMap("key", "value2").build();
+    Foo foo4 = Foo.newBuilder().setMyGroup(Foo.MyGroup.newBuilder().setValue(4).build()).build();
+
+    assertEqualsAndHashCodeAreFalse(foo1, foo2);
+    assertEqualsAndHashCodeAreFalse(foo1, foo3);
+    assertEqualsAndHashCodeAreFalse(foo1, foo4);
+  }
+
+  public void testOneofEquals() throws Exception {
+    TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+    TestOneofEquals message1 = builder.build();
+    // Set message2's name field to default value. The two messages should be different when we
+    // check with the oneof case.
+    builder.setName("");
+    TestOneofEquals message2 = builder.build();
+    assertFalse(message1.equals(message2));
+  }
+
+  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());
+
     assertEquals(
-        11, (int) extendableMessage.getExtension(
-            UnittestLite.optionalFixed32ExtensionLite));
+        one.toBuilder().mergeFrom(two).build(),
+        two.toBuilder().mergeFrom(two.toByteArray()).build());
+  }
+
+  public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
+    Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
+
+    Foo fooWithValueAndExtension =
+        fooWithOnlyValue
+            .toBuilder()
+            .setValue(1)
+            .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
+            .build();
+
+    Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray());
+
+    assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields);
+    assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
+  }
+
+  public void testEqualsAndHashCodeWithExtensions() throws InvalidProtocolBufferException {
+    Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
+
+    Foo fooWithValueAndExtension =
+        fooWithOnlyValue
+            .toBuilder()
+            .setValue(1)
+            .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
+            .build();
+
+    assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndExtension);
+  }
+
+  // Test to ensure we avoid a class cast exception with oneofs.
+  public void testEquals_oneOfMessages() {
+    TestAllTypesLite mine = TestAllTypesLite.newBuilder().setOneofString("Hello").build();
+
+    TestAllTypesLite other =
+        TestAllTypesLite.newBuilder()
+            .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+            .build();
+
+    assertFalse(mine.equals(other));
+    assertFalse(other.equals(mine));
+  }
+
+  public void testHugeFieldNumbers() throws InvalidProtocolBufferException {
+    TestHugeFieldNumbersLite message =
+        TestHugeFieldNumbersLite.newBuilder()
+            .setOptionalInt32(1)
+            .addRepeatedInt32(2)
+            .setOptionalEnum(ForeignEnumLite.FOREIGN_LITE_FOO)
+            .setOptionalString("xyz")
+            .setOptionalMessage(ForeignMessageLite.newBuilder().setC(3).build())
+            .build();
+
+    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());
+  }
+
+  private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
+    assertFalse(o1.equals(o2));
+    assertFalse(o1.hashCode() == o2.hashCode());
+  }
+
+  public void testRecursiveHashcode() {
+    // This tests that we don't infinite loop.
+    TestRecursiveOneof.getDefaultInstance().hashCode();
+  }
+
+  public void testParseFromByteBuffer() throws Exception {
+    TestAllTypesLite message =
+        TestAllTypesLite.newBuilder()
+            .setOptionalInt32(123)
+            .addRepeatedString("hello")
+            .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+            .build();
+
+    TestAllTypesLite copy =
+        TestAllTypesLite.parseFrom(message.toByteString().asReadOnlyByteBuffer());
+
+    assertEquals(message, copy);
+  }
+
+  public void testParseFromByteBufferThrows() {
+    try {
+      TestAllTypesLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}));
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+    }
+
+    TestAllTypesLite message =
+        TestAllTypesLite.newBuilder().setOptionalInt32(123).addRepeatedString("hello").build();
+
+    ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
+    try {
+      TestAllTypesLite.parseFrom(buffer);
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertEquals(
+          TestAllTypesLite.newBuilder().setOptionalInt32(123).build(),
+          expected.getUnfinishedMessage());
+    }
+  }
+
+  public void testParseFromByteBuffer_extensions() throws Exception {
+    TestAllExtensionsLite message =
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+            .setExtension(
+                UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
+            .setExtension(
+                UnittestLite.optionalNestedMessageExtensionLite,
+                TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+            .build();
+
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+
+    TestAllExtensionsLite copy =
+        TestAllExtensionsLite.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry);
+
+    assertEquals(message, copy);
+  }
+
+  public void testParseFromByteBufferThrows_extensions() {
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+    try {
+      TestAllExtensionsLite.parseFrom(ByteBuffer.wrap(new byte[] {0x5}), registry);
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+    }
+
+    TestAllExtensionsLite message =
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+            .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+            .build();
+
+    ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
+    try {
+      TestAllExtensionsLite.parseFrom(buffer, registry);
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertEquals(
+          TestAllExtensionsLite.newBuilder()
+              .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+              .build(),
+          expected.getUnfinishedMessage());
+    }
+  }
+
+  // Make sure we haven't screwed up the code generation for packing fields by default.
+  public void testPackedSerialization() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addRepeatedInt32(4321);
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
+    TestAllTypes message = builder.build();
+
+    CodedInputStream in = CodedInputStream.newInstance(message.toByteArray());
+
+    while (!in.isAtEnd()) {
+      int tag = in.readTag();
+      assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag));
+      in.skipField(tag);
+    }
+  }
+
+  public void testAddAllIteratesOnce() {
+    TestAllTypesLite.newBuilder()
+        .addAllRepeatedBool(new OneTimeIterableList(false))
+        .addAllRepeatedInt32(new OneTimeIterableList(0))
+        .addAllRepeatedInt64(new OneTimeIterableList(0L))
+        .addAllRepeatedFloat(new OneTimeIterableList(0f))
+        .addAllRepeatedDouble(new OneTimeIterableList(0d))
+        .addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY))
+        .addAllRepeatedString(new OneTimeIterableList(""))
+        .addAllRepeatedNestedMessage(new OneTimeIterableList(NestedMessage.getDefaultInstance()))
+        .addAllRepeatedBool(new OneTimeIterable(false))
+        .addAllRepeatedInt32(new OneTimeIterable(0))
+        .addAllRepeatedInt64(new OneTimeIterable(0L))
+        .addAllRepeatedFloat(new OneTimeIterable(0f))
+        .addAllRepeatedDouble(new OneTimeIterable(0d))
+        .addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY))
+        .addAllRepeatedString(new OneTimeIterable(""))
+        .addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance()))
+        .build();
+  }
+
+  public void testAddAllIteratesOnce_throwsOnNull() {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    try {
+      builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 2 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedBoolCount());
+    }
+
+    try {
+      builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 2 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedBoolCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedBoolCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedInt32Count());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedInt64Count());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedFloatCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedDoubleCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedBytesCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, ""));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 2 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedStringCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, ""));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 2 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedStringCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedString(new OneTimeIterableList((String) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedStringCount());
+    }
+
+    try {
+      builder = TestAllTypesLite.newBuilder();
+      builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null));
+      fail();
+    } catch (NullPointerException expected) {
+      assertEquals("Element at index 0 is null.", expected.getMessage());
+      assertEquals(0, builder.getRepeatedNestedMessageCount());
+    }
+  }
+
+  private static final class OneTimeIterableList<T> extends ArrayList<T> {
+    private boolean wasIterated = false;
+
+    OneTimeIterableList(T... contents) {
+      addAll(Arrays.asList(contents));
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+      if (wasIterated) {
+        fail();
+      }
+      wasIterated = true;
+      return super.iterator();
+    }
+  }
+
+  private static final class OneTimeIterable<T> implements Iterable<T> {
+    private final List<T> list;
+    private boolean wasIterated = false;
+
+    OneTimeIterable(T... contents) {
+      list = Arrays.asList(contents);
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+      if (wasIterated) {
+        fail();
+      }
+      wasIterated = true;
+      return list.iterator();
+    }
+  }
+
+  public void testNullExtensionRegistry() throws Exception {
+    try {
+      TestAllTypesLite.parseFrom(new byte[] {}, null);
+      fail();
+    } catch (NullPointerException expected) {
+    }
   }
 }
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 68b55ce..eac4744 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -30,8 +30,6 @@
 
 package com.google.protobuf;
 
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
@@ -45,11 +43,12 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
+import junit.framework.TestCase;
 
 /**
- * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
- * This class is designed to be extended for testing extensions of {@link LiteralByteString}
- * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
+ * 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 carlanton@google.com (Carl Haverl)
  */
@@ -304,25 +303,75 @@
         Arrays.equals(referenceBytes, roundTripBytes));
   }
 
-  public void testWriteTo_mutating() throws IOException {
+  public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
     OutputStream os = new OutputStream() {
       @Override
       public void write(byte[] b, int off, int len) {
-        for (int x = 0; x < len; ++x) {
-          b[off + x] = (byte) 0;
-        }
+        Arrays.fill(b, off, off + len, (byte) 0);
       }
 
       @Override
       public void write(int b) {
-        // Purposefully left blank.
+        throw new UnsupportedOperationException();
       }
     };
 
     stringUnderTest.writeTo(os);
-    byte[] newBytes = stringUnderTest.toByteArray();
     assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
-        Arrays.equals(referenceBytes, newBytes));
+        Arrays.equals(referenceBytes, stringUnderTest.toByteArray()));
+  }
+
+  public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    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()));
+  }
+
+  public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+    ByteOutput out = new ByteOutput() {
+      @Override
+      public void write(byte value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(byte[] value, int offset, int length) throws IOException {
+        Arrays.fill(value, offset, offset + length, (byte) 0);
+      }
+
+      @Override
+      public void write(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    stringUnderTest.writeTo(out);
+    byte[] allZeros = new byte[stringUnderTest.size()];
+    assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
+        Arrays.equals(allZeros, stringUnderTest.toByteArray()));
   }
 
   public void testNewOutput() throws IOException {
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 1bd094f..e50c7d1 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -32,70 +32,57 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
+import com.google.protobuf.Internal.LongList;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link LongArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class LongArrayListTest extends TestCase {
-  
-  private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1);
+
+  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 {
     list = new LongArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(LongArrayList.emptyList(), LongArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(LongArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addLong(2);
+    list.addLong(3);
     list.addLong(4);
-    list.addLong(6);
-    list.addLong(8);
+    list.addLong(5);
+    list.addLong(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
-  public void testCopyConstructor() {
-    LongArrayList copy = new LongArrayList(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
 
-    copy = new LongArrayList(LongArrayList.emptyList());
-    assertEquals(LongArrayList.emptyList(), copy);
-    
-    copy = new LongArrayList(asList(1L, 2L, 3L));
-    assertEquals(asList(1L, 2L, 3L), copy);
-
-    copy = new LongArrayList(Collections.<Long>emptyList());
-    assertEquals(LongArrayList.emptyList(), copy);
-  }
-  
   public void testModificationWithIteration() {
     list.addAll(asList(1L, 2L, 3L, 4L));
     Iterator<Long> iterator = list.iterator();
     assertEquals(4, list.size());
-    assertEquals(1, (long) list.get(0));
-    assertEquals(1, (long) iterator.next());
+    assertEquals(1L, (long) list.get(0));
+    assertEquals(1L, (long) iterator.next());
     list.set(0, 1L);
-    assertEquals(2, (long) iterator.next());
-    
+    assertEquals(2L, (long) iterator.next());
+
     list.remove(0);
     try {
       iterator.next();
@@ -103,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0L);
     try {
@@ -113,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
-    assertEquals(1, (long) TERTIARY_LIST.get(0));
-    assertEquals(2, (long) TERTIARY_LIST.get(1));
-    assertEquals(3, (long) TERTIARY_LIST.get(2));
-    
+    assertEquals(1L, (long) TERTIARY_LIST.get(0));
+    assertEquals(2L, (long) TERTIARY_LIST.get(1));
+    assertEquals(3L, (long) TERTIARY_LIST.get(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -133,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetLong() {
-    assertEquals(1, TERTIARY_LIST.getLong(0));
-    assertEquals(2, TERTIARY_LIST.getLong(1));
-    assertEquals(3, TERTIARY_LIST.getLong(2));
-    
+    assertEquals(1L, TERTIARY_LIST.getLong(0));
+    assertEquals(2L, TERTIARY_LIST.getLong(1));
+    assertEquals(3L, TERTIARY_LIST.getLong(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -153,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, LongArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addLong(2);
+    list.addLong(3);
     list.addLong(4);
     list.addLong(6);
     list.addLong(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16L);
+
+    list.add(17L);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addLong(2);
     list.addLong(4);
-    
-    assertEquals(2, (long) list.set(0, 0L));
-    assertEquals(0, list.getLong(0));
 
-    assertEquals(4, (long) list.set(1, 0L));
-    assertEquals(0, list.getLong(1));
-    
+    assertEquals(2L, (long) list.set(0, 3L));
+    assertEquals(3L, list.getLong(0));
+
+    assertEquals(4L, (long) list.set(1, 0L));
+    assertEquals(0L, list.getLong(1));
+
     try {
       list.set(-1, 0L);
       fail();
@@ -196,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetLong() {
-    list.addLong(2);
-    list.addLong(4);
-    
-    assertEquals(2, list.setLong(0, 0));
-    assertEquals(0, list.getLong(0));
 
-    assertEquals(4, list.setLong(1, 0));
-    assertEquals(0, list.getLong(1));
-    
+  public void testSetLong() {
+    list.addLong(1);
+    list.addLong(3);
+
+    assertEquals(1L, list.setLong(0, 0));
+    assertEquals(0L, list.getLong(0));
+
+    assertEquals(3L, list.setLong(1, 0));
+    assertEquals(0L, list.getLong(1));
+
     try {
       list.setLong(-1, 0);
       fail();
@@ -221,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -231,28 +218,30 @@
     assertTrue(list.add(3L));
     list.add(0, 4L);
     assertEquals(asList(4L, 2L, 3L), list);
-    
+
     list.add(0, 1L);
     list.add(0, 0L);
     // Force a resize by getting up to 11 elements.
     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);
-    
+    assertEquals(
+        asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L),
+        list);
+
     try {
       list.add(-1, 5L);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5L);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddLong() {
     assertEquals(0, list.size());
 
@@ -262,128 +251,142 @@
     list.addLong(3);
     assertEquals(asList(2L, 3L), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
     assertTrue(list.addAll(Collections.singleton(1L)));
     assertEquals(1, list.size());
-    assertEquals(1, (long) list.get(0));
-    assertEquals(1, list.getLong(0));
-    
+    assertEquals(1L, (long) list.get(0));
+    assertEquals(1L, list.getLong(0));
+
     assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L)));
     assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list);
 
     assertFalse(list.addAll(Collections.<Long>emptyList()));
     assertFalse(list.addAll(LongArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1, (long) list.remove(0));
+    assertEquals(1L, (long) list.remove(0));
     assertEquals(asList(2L, 3L), list);
 
-    assertTrue(list.remove(3L));
+    assertTrue(list.remove(Long.valueOf(3)));
     assertEquals(asList(2L), list);
 
-    assertFalse(list.remove(3L));
+    assertFalse(list.remove(Long.valueOf(3)));
     assertEquals(asList(2L), list);
 
-    assertEquals(2, (long) list.remove(0));
+    assertEquals(2L, (long) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
+  public void testRemoveEndOfCapacity() {
+    LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addLong(3);
+    toRemove.remove(0);
+    assertEquals(0, toRemove.size());
+  }
+
+  public void testSublistRemoveEndOfCapacity() {
+    LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+    toRemove.addLong(3);
+    toRemove.subList(0, 1).clear();
+    assertEquals(0, toRemove.size());
+  }
+
   private void assertImmutable(LongArrayList list) {
     if (list.contains(1L)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new LongArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addLong(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -397,63 +400,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setLong(0, 0);
       fail();
@@ -461,7 +464,7 @@
       // expected
     }
   }
-  
+
   private static LongArrayList newImmutableLongArrayList(long... elements) {
     LongArrayList list = new LongArrayList();
     for (long element : elements) {
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 3d8c9bc..da9195f 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -30,48 +30,56 @@
 
 package com.google.protobuf;
 
+import map_lite_test.MapForProto2TestProto.BizarroTestMap;
 import map_lite_test.MapForProto2TestProto.TestMap;
 import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
+import map_lite_test.MapForProto2TestProto.TestMapOrBuilder;
 import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue;
-
-import junit.framework.TestCase;
-
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Unit tests for map fields.
  */
-public class MapForProto2LiteTest extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
-    builder.getMutableInt32ToInt32Field().put(1, 11);
-    builder.getMutableInt32ToInt32Field().put(2, 22);
-    builder.getMutableInt32ToInt32Field().put(3, 33);
+public final class MapForProto2LiteTest extends TestCase {
 
-    builder.getMutableInt32ToStringField().put(1, "11");
-    builder.getMutableInt32ToStringField().put(2, "22");
-    builder.getMutableInt32ToStringField().put(3, "33");
-    
-    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
-    builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
-    builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-    
-    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
-    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
-    builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-    
-    builder.getMutableInt32ToMessageField().put(
-        1, MessageValue.newBuilder().setValue(11).build());
-    builder.getMutableInt32ToMessageField().put(
-        2, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        3, MessageValue.newBuilder().setValue(33).build());
-    
-    builder.getMutableStringToInt32Field().put("1", 11);
-    builder.getMutableStringToInt32Field().put("2", 22);
-    builder.getMutableStringToInt32Field().put("3", 33);
+  private void setMapValues(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    setMapValues(mapBuilder);
+    TestMap map = mapBuilder.build();
+    assertMapValuesSet(map);
   }
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
@@ -94,22 +102,22 @@
     assertEquals("11", message.getInt32ToStringField().get(1));
     assertEquals("22", message.getInt32ToStringField().get(2));
     assertEquals("33", message.getInt32ToStringField().get(3));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(11, message.getStringToInt32Field().get("1").intValue());
     assertEquals(22, message.getStringToInt32Field().get("2").intValue());
@@ -117,31 +125,42 @@
   }
 
   private void updateMapValues(TestMap.Builder builder) {
-    builder.getMutableInt32ToInt32Field().put(1, 111);
-    builder.getMutableInt32ToInt32Field().remove(2);
-    builder.getMutableInt32ToInt32Field().put(4, 44);
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
 
-    builder.getMutableInt32ToStringField().put(1, "111");
-    builder.getMutableInt32ToStringField().remove(2);
-    builder.getMutableInt32ToStringField().put(4, "44");
-    
-    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
-    builder.getMutableInt32ToBytesField().remove(2);
-    builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-    
-    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
-    builder.getMutableInt32ToEnumField().remove(2);
-    builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-    
-    builder.getMutableInt32ToMessageField().put(
-        1, MessageValue.newBuilder().setValue(111).build());
-    builder.getMutableInt32ToMessageField().remove(2);
-    builder.getMutableInt32ToMessageField().put(
-        4, MessageValue.newBuilder().setValue(44).build());
-    
-    builder.getMutableStringToInt32Field().put("1", 111);
-    builder.getMutableStringToInt32Field().remove("2");
-    builder.getMutableStringToInt32Field().put("4", 44);
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    setMapValues(mapBuilder);
+    TestMap map = mapBuilder.build();
+    assertMapValuesSet(map);
+
+    mapBuilder = map.toBuilder();
+    updateMapValues(mapBuilder);
+    map = mapBuilder.build();
+    assertMapValuesUpdated(map);
   }
 
   private void assertMapValuesUpdated(TestMap message) {
@@ -154,188 +173,149 @@
     assertEquals("111", message.getInt32ToStringField().get(1));
     assertEquals("33", message.getInt32ToStringField().get(3));
     assertEquals("44", message.getInt32ToStringField().get(4));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
     assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
     assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
     assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(111, message.getStringToInt32Field().get("1").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
 
   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
     // a produced message.
-    
+
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
-    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
-    intMap.put(1, 2);
+    builder.putInt32ToInt32Field(1, 2);
     assertTrue(message.getInt32ToInt32Field().isEmpty());
     message = builder.build();
-    try {
-      intMap.put(2, 3);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    builder.getMutableInt32ToInt32Field().put(2, 3);
+    builder.putInt32ToInt32Field(2, 3);
     assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
   }
-  
-  public void testMutableMapLifecycle() {
+
+  public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
-    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
-    intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValues(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
-      intMap.put(2, 3);
+      map.put(key, value);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
+    if (!map.isEmpty()) {
+      try {
+        map.entrySet().remove(map.entrySet().iterator().next());
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+  }
+
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    builder.getMutableInt32ToInt32Field().put(2, 3);
+    builder.putInt32ToInt32Field(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
 
-    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
-    enumMap.put(1, TestMap.EnumValue.BAR);
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
-    try {
-      enumMap.put(2, TestMap.EnumValue.FOO);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
-    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
-    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
-    stringMap.put(1, "1");
+
+    builder.putInt32ToStringField(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
-    try {
-      stringMap.put(2, "2");
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
-    builder.getMutableInt32ToStringField().put(2, "2");
-    assertEquals(
-        newMap(1, "1", 2, "2"),
-        builder.getInt32ToStringField());
-    
-    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
-    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToStringField(2, "2");
+    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField());
+
+    builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.build().getInt32ToMessageField());
-    try {
-      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
-    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
 
-  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());
-    try {
-      intMap.remove(2);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.entrySet().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.entrySet().iterator().remove();
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.keySet().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.values().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.values().iterator().remove();
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    assertEquals(newMap(1, 2), intMap);
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
-  }
-
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
-    
+
     builder = message.toBuilder();
     setMapValues(builder);
     message = builder.build();
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
@@ -344,12 +324,52 @@
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValues(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
     assertMapValuesSet(destination.build());
   }
 
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+  }
+
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -357,14 +377,14 @@
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
@@ -372,12 +392,61 @@
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
-  
+
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  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));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    
+
     TestMap.Builder other = TestMap.newBuilder();
     other.mergeFrom(message);
     assertMapValuesSet(other.build());
@@ -386,26 +455,26 @@
   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.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap.Builder b1 = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
-    
-    TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+
+    TestMap.Builder b2 = TestMap.newBuilder()
+        .putInt32ToInt32Field(5, 6)
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
@@ -413,10 +482,9 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 1);
-    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
+        .putInt32ToInt32Field(1, 1)
+        .putInt32ToInt32Field(2, 54321);
     ByteString data = builder.build().toByteString();
 
     TestMap message = TestMap.parseFrom(data);
@@ -432,7 +500,6 @@
     assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
   }
-  
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
@@ -442,17 +509,288 @@
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
+
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValues(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  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());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValues(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValues(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      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 1fa3cbd..bcfd927 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -31,53 +31,99 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapForProto2TestProto.BizarroTestMap;
+import map_test.MapForProto2TestProto.ReservedAsMapField;
+import map_test.MapForProto2TestProto.ReservedAsMapFieldWithEnumValue;
 import map_test.MapForProto2TestProto.TestMap;
 import map_test.MapForProto2TestProto.TestMap.MessageValue;
 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
+import map_test.MapForProto2TestProto.TestMapOrBuilder;
 import map_test.MapForProto2TestProto.TestRecursiveMap;
 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
-
-import junit.framework.TestCase;
-
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Unit tests for map fields in proto2 protos.
  */
 public class MapForProto2Test extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
+
+  private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "11");
     builder.getMutableInt32ToStringField().put(2, "22");
     builder.getMutableInt32ToStringField().put(3, "33");
-    
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-    
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-    
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(11).build());
     builder.getMutableInt32ToMessageField().put(
         2, MessageValue.newBuilder().setValue(22).build());
     builder.getMutableInt32ToMessageField().put(
         3, MessageValue.newBuilder().setValue(33).build());
-    
+  //
     builder.getMutableStringToInt32Field().put("1", 11);
     builder.getMutableStringToInt32Field().put("2", 22);
     builder.getMutableStringToInt32Field().put("3", 33);
   }
 
+  private void setMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
         .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
@@ -88,7 +134,7 @@
         .putAllStringToInt32Field(source.getStringToInt32Field());
   }
 
-  private void assertMapValuesSet(TestMap message) {
+  private void assertMapValuesSet(TestMapOrBuilder message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
     assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
@@ -98,56 +144,109 @@
     assertEquals("11", message.getInt32ToStringField().get(1));
     assertEquals("22", message.getInt32ToStringField().get(2));
     assertEquals("33", message.getInt32ToStringField().get(3));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(11, message.getStringToInt32Field().get("1").intValue());
     assertEquals(22, message.getStringToInt32Field().get("2").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
   }
 
-  private void updateMapValues(TestMap.Builder builder) {
+  private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "111");
     builder.getMutableInt32ToStringField().remove(2);
     builder.getMutableInt32ToStringField().put(4, "44");
-    
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
     builder.getMutableInt32ToBytesField().remove(2);
     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-    
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().remove(2);
     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-    
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(111).build());
     builder.getMutableInt32ToMessageField().remove(2);
     builder.getMutableInt32ToMessageField().put(
         4, MessageValue.newBuilder().setValue(44).build());
-    
+  //
     builder.getMutableStringToInt32Field().put("1", 111);
     builder.getMutableStringToInt32Field().remove("2");
     builder.getMutableStringToInt32Field().put("4", 44);
   }
 
+  private void updateMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
+
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+    //
+    usingMutableMapBuilder = usingMutableMap.toBuilder();
+    updateMapValuesUsingMutableMap(usingMutableMapBuilder);
+    usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesUpdated(usingMutableMap);
+
+    usingAccessorsBuilder = usingAccessors.toBuilder();
+    updateMapValuesUsingAccessors(usingAccessorsBuilder);
+    usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesUpdated(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void assertMapValuesUpdated(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
@@ -158,37 +257,72 @@
     assertEquals("111", message.getInt32ToStringField().get(1));
     assertEquals("33", message.getInt32ToStringField().get(3));
     assertEquals("44", message.getInt32ToStringField().get(4));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
     assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
     assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
     assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(111, message.getStringToInt32Field().get("1").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
-  
+
+  public void testGetMapIsImmutable() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValuesUsingAccessors(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
+    try {
+      map.put(key, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -203,7 +337,7 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     builder.getMutableInt32ToInt32Field().put(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
-
+ //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -218,7 +352,7 @@
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
+  //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -233,7 +367,7 @@
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-    
+  //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -252,7 +386,7 @@
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
-
+  //
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -299,52 +433,96 @@
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
 
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
-    
+
     builder = message.toBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValues(sourceBuilder);
+    setMapValuesUsingAccessors(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
     assertMapValuesSet(destination.build());
+
+    assertEquals(3, destination.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
   }
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
@@ -352,12 +530,61 @@
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
-  
+
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  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));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    
+
     TestMap.Builder other = TestMap.newBuilder();
     other.mergeFrom(message);
     assertMapValuesSet(other.build());
@@ -366,51 +593,51 @@
   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.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    b1.putInt32ToInt32Field(1, 2);
+    b1.putInt32ToInt32Field(3, 4);
+    b1.putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
-    
+
     TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+    b2.putInt32ToInt32Field(5, 6);
+    b2.putInt32ToInt32Field(1, 2);
+    b2.putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
-  
-  
+
+
   // The following methods are used to test reflection API.
-  
+
   private static FieldDescriptor f(String name) {
     return TestMap.getDescriptor().findFieldByName(name);
   }
-  
+
   private static Object getFieldValue(Message mapEntry, String name) {
     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
     return mapEntry.getField(field);
   }
-  
+
   private static Message.Builder setFieldValue(
       Message.Builder mapEntry, String name, Object value) {
     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
     mapEntry.setField(field, value);
     return mapEntry;
   }
-  
+
   private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
     FieldDescriptor field = f(name);
     for (Object entry : (List<?>) message.getField(field)) {
@@ -429,7 +656,7 @@
       assertEquals(value, values.get(key));
     }
   }
-  
+
   private static <KeyType, ValueType>
   Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
@@ -440,7 +667,7 @@
     entryBuilder.setField(valueField, value);
     return entryBuilder.build();
   }
-  
+
   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
     List<Message> entryList = new ArrayList<Message>();
     for (Map.Entry<?, ?> entry : values.entrySet()) {
@@ -449,9 +676,8 @@
     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
     builder.setField(field, entryList);
   }
-  
-  private static <KeyType, ValueType>
-  Map<KeyType, ValueType> mapForValues(
+
+  private static <KeyType, ValueType> Map<KeyType, ValueType> mapForValues(
       KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
     Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
     map.put(key1, value1);
@@ -461,13 +687,11 @@
 
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 2);
-    builder.getMutableInt32ToInt32Field().put(3, 4);
-    builder.getMutableInt32ToMessageField().put(
-        11, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
     TestMap message = builder.build();
 
     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
@@ -477,14 +701,14 @@
         mapForValues(
             11, MessageValue.newBuilder().setValue(22).build(),
             33, MessageValue.newBuilder().setValue(44).build()));
-    
+
     // Test clearField()
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
     assertEquals(0, message.getInt32ToInt32Field().size());
     assertEquals(0, message.getInt32ToMessageField().size());
-    
+
     // Test setField()
     setMapValues(builder, "int32_to_int32_field",
         mapForValues(11, 22, 33, 44));
@@ -497,7 +721,7 @@
     assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
     assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
     assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
-    
+
     // Test addRepeatedField
     builder.addRepeatedField(f("int32_to_int32_field"),
         newMapEntry(builder, "int32_to_int32_field", 55, 66));
@@ -517,7 +741,7 @@
     message = builder.build();
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
     assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
-    
+
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
       Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
@@ -534,35 +758,54 @@
     assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
   }
-  
+
+  // See additional coverage in TextFormatTest.java.
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    
+
     String textData = TextFormat.printToString(message);
-    
+
     builder = TestMap.newBuilder();
     TextFormat.merge(textData, builder);
     message = builder.build();
-    
+
     assertMapValuesSet(message);
   }
-  
+
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    
+
     Message dynamicDefaultInstance =
         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     Message dynamicMessage = dynamicDefaultInstance
         .newBuilderForType().mergeFrom(message.toByteString()).build();
-    
+
     assertEquals(message, dynamicMessage);
     assertEquals(message.hashCode(), dynamicMessage.hashCode());
   }
-  
+
+  // Check that DynamicMessage handles map field serialization the same way as generated code
+  // regarding unset key and value field in a map entry.
+  public void testDynamicMessageUnsetKeyAndValue() throws Exception {
+    FieldDescriptor field = f("int32_to_int32_field");
+
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
+    // Add an entry without key and value.
+    builder.addRepeatedField(field, builder.newBuilderForField(field).build());
+    Message message = builder.build();
+    ByteString bytes = message.toByteString();
+    // Parse it back to the same generated type.
+    Message generatedMessage = TestMap.parseFrom(bytes);
+    // Assert the serialized bytes are equivalent.
+    assertEquals(generatedMessage.toByteString(), bytes);
+  }
+
   public void testReflectionEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -571,22 +814,22 @@
     Message dynamicDefaultInstance =
         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     FieldDescriptor field = f("int32_to_int32_field");
-    
+
     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
     Message m1 = b1.build();
-    
+
     Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
     Message m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
     m2 = b2.build();
@@ -594,12 +837,11 @@
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
-  
+
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 1);
-    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
+        .putInt32ToInt32Field(1, 1)
+        .putInt32ToInt32Field(2, 54321);
     ByteString data = builder.build().toByteString();
 
     TestMap message = TestMap.parseFrom(data);
@@ -618,26 +860,21 @@
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
   }
 
-
   public void testRequiredMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableRequiredMessageMap().put(0,
-        MessageWithRequiredFields.newBuilder().buildPartial());
+    builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().buildPartial());
     TestMap message = builder.buildPartial();
     assertFalse(message.isInitialized());
 
-    builder.getMutableRequiredMessageMap().put(0,
-        MessageWithRequiredFields.newBuilder().setValue(1).build());
+    builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().setValue(1).build());
     message = builder.build();
     assertTrue(message.isInitialized());
   }
 
   public void testRecursiveMap() throws Exception {
     TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
-    builder.getMutableRecursiveMapField().put(
-        1, TestRecursiveMap.newBuilder().setValue(2).build());
-    builder.getMutableRecursiveMapField().put(
-        3, TestRecursiveMap.newBuilder().setValue(4).build());
+    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);
@@ -647,13 +884,266 @@
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
 
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValuesUsingAccessors(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  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());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
   // Regression test for b/20494788
   public void testMapInitializationOrder() throws Exception {
     assertEquals("RedactAllTypes", map_test.RedactAllTypes
@@ -661,24 +1151,47 @@
 
     map_test.Message1.Builder builder =
         map_test.Message1.newBuilder();
-    builder.getMutableMapField().put("key", true);
+    builder.putMapField("key", true);
     map_test.Message1 message = builder.build();
     Message mapEntry = (Message) message.getRepeatedField(
         message.getDescriptorForType().findFieldByName("map_field"), 0);
     assertEquals(2, mapEntry.getAllFields().size());
   }
-  
+
+  public void testReservedWordsFieldNames() {
+    ReservedAsMapField.newBuilder().build();
+    ReservedAsMapFieldWithEnumValue.newBuilder().build();
+  }
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
-}
 
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertMapValuesSet(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+}
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 0e5c128..58efce9 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -30,55 +30,102 @@
 
 package com.google.protobuf;
 
+import static org.junit.Assert.assertArrayEquals;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapTestProto.BizarroTestMap;
+import map_test.MapTestProto.ReservedAsMapField;
+import map_test.MapTestProto.ReservedAsMapFieldWithEnumValue;
 import map_test.MapTestProto.TestMap;
 import map_test.MapTestProto.TestMap.MessageValue;
+import map_test.MapTestProto.TestMapOrBuilder;
 import map_test.MapTestProto.TestOnChangeEventPropagation;
-
-import junit.framework.TestCase;
-
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Unit tests for map fields.
  */
 public class MapTest extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
+
+  private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "11");
     builder.getMutableInt32ToStringField().put(2, "22");
     builder.getMutableInt32ToStringField().put(3, "33");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(11).build());
     builder.getMutableInt32ToMessageField().put(
         2, MessageValue.newBuilder().setValue(22).build());
     builder.getMutableInt32ToMessageField().put(
         3, MessageValue.newBuilder().setValue(33).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 11);
     builder.getMutableStringToInt32Field().put("2", 22);
     builder.getMutableStringToInt32Field().put("3", 33);
   }
 
+  private void setMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
         .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
@@ -121,34 +168,87 @@
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
   }
 
-  private void updateMapValues(TestMap.Builder builder) {
+  private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "111");
     builder.getMutableInt32ToStringField().remove(2);
     builder.getMutableInt32ToStringField().put(4, "44");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
     builder.getMutableInt32ToBytesField().remove(2);
     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().remove(2);
     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(111).build());
     builder.getMutableInt32ToMessageField().remove(2);
     builder.getMutableInt32ToMessageField().put(
         4, MessageValue.newBuilder().setValue(44).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 111);
     builder.getMutableStringToInt32Field().remove("2");
     builder.getMutableStringToInt32Field().put("4", 44);
   }
 
+  private void updateMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
+
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+    //
+    usingMutableMapBuilder = usingMutableMap.toBuilder();
+    updateMapValuesUsingMutableMap(usingMutableMapBuilder);
+    usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesUpdated(usingMutableMap);
+
+    usingAccessorsBuilder = usingAccessors.toBuilder();
+    updateMapValuesUsingAccessors(usingAccessorsBuilder);
+    usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesUpdated(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void assertMapValuesUpdated(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
@@ -181,15 +281,50 @@
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
-  
+
+  public void testGetMapIsImmutable() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValuesUsingAccessors(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
+    try {
+      map.put(key, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -204,7 +339,7 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     builder.getMutableInt32ToInt32Field().put(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
-
+  //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -219,7 +354,7 @@
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
+  //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -230,11 +365,11 @@
       // expected
     }
     assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
-    builder.getMutableInt32ToStringField().put(2, "2");
+    builder.putInt32ToStringField(2, "2");
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-    
+  //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -247,13 +382,13 @@
     }
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
-    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
-
+  //
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -299,32 +434,35 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
-  
+
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
 
     builder = message.toBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValues(sourceBuilder);
+    setMapValuesUsingAccessors(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
@@ -332,31 +470,84 @@
   }
 
   public void testPutAllForUnknownEnumValues() throws Exception {
-    TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(0, 0);
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(1, 1);
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
-    TestMap source = sourceBuilder.build();
+    TestMap source = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(newMap(
+            0, 0,
+            1, 1,
+            2, 1000)) // unknown value.
+        .build();
 
-    TestMap.Builder destinationBuilder = TestMap.newBuilder();
-    destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue());
-    TestMap destination = destinationBuilder.build();
+    TestMap destination = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue())
+        .build();
 
     assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
     assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
     assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(3, destination.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutForUnknownEnumValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToEnumFieldValue(0, 0)
+        .putInt32ToEnumFieldValue(1, 1)
+        .putInt32ToEnumFieldValue(2, 1000);  // unknown value.
+    TestMap message = builder.build();
+    assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
+    assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
+    assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
+    assertEquals(3, message.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
   }
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
@@ -370,9 +561,58 @@
     assertMapValuesCleared(message);
   }
 
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  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));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     TestMap.Builder other = TestMap.newBuilder();
@@ -386,23 +626,23 @@
 
     // 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.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap.Builder b1 = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
 
-    TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+    TestMap.Builder b2 = TestMap.newBuilder()
+        .putInt32ToInt32Field(5, 6)
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
 
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
@@ -410,7 +650,7 @@
 
     // Regression test for b/18549190: if a map is a subset of the other map,
     // equals() should return false.
-    b2.getMutableInt32ToInt32Field().remove(1);
+    b2.removeInt32ToInt32Field(1);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     assertFalse(m2.equals(m1));
@@ -419,20 +659,19 @@
   public void testNestedBuilderOnChangeEventPropagation() {
     TestOnChangeEventPropagation.Builder parent =
         TestOnChangeEventPropagation.newBuilder();
-    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 2);
+    parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2);
     TestOnChangeEventPropagation message = parent.build();
     assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
 
     // Make a change using nested builder.
-    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 3);
+    parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3);
 
     // Should be able to observe the change.
     message = parent.build();
     assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
 
     // Make another change using mergeFrom()
-    TestMap.Builder other = TestMap.newBuilder();
-    other.getMutableInt32ToInt32Field().put(1, 4);
+    TestMap.Builder other = TestMap.newBuilder().putInt32ToInt32Field(1, 4);
     parent.getOptionalMessageBuilder().mergeFrom(other.build());
 
     // Should be able to observe the change.
@@ -455,8 +694,7 @@
     TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder();
 
     // Create a map entry message.
-    TestMap.Builder entryBuilder = TestMap.newBuilder();
-    entryBuilder.getMutableInt32ToInt32Field().put(1, 1);
+    TestMap.Builder entryBuilder = TestMap.newBuilder().putInt32ToInt32Field(1, 1);
 
     // Put the entry into the nested builder.
     testMapBuilder.addRepeatedField(
@@ -467,7 +705,7 @@
     assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size());
 
     // Change the entry value.
-    entryBuilder.getMutableInt32ToInt32Field().put(1, 4);
+    entryBuilder.putInt32ToInt32Field(1, 4);
     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
     testMapBuilder.setRepeatedField(
         intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0));
@@ -554,13 +792,11 @@
 
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 2);
-    builder.getMutableInt32ToInt32Field().put(3, 4);
-    builder.getMutableInt32ToMessageField().put(
-        11, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
     TestMap message = builder.build();
 
     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
@@ -628,9 +864,10 @@
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
   }
 
+  // See additional coverage in TextFormatTest.java.
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     String textData = TextFormat.printToString(message);
@@ -644,7 +881,7 @@
 
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     Message dynamicDefaultInstance =
@@ -656,6 +893,24 @@
     assertEquals(message.hashCode(), dynamicMessage.hashCode());
   }
 
+  // Check that DynamicMessage handles map field serialization the same way as generated code
+  // regarding unset key and value field in a map entry.
+  public void testDynamicMessageUnsetKeyAndValue() throws Exception {
+    FieldDescriptor field = f("int32_to_int32_field");
+
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
+    // Add an entry without key and value.
+    builder.addRepeatedField(field, builder.newBuilderForField(field).build());
+    Message message = builder.build();
+    ByteString bytes = message.toByteString();
+    // Parse it back to the same generated type.
+    Message generatedMessage = TestMap.parseFrom(bytes);
+    // Assert the serialized bytes are equivalent.
+    assertEquals(generatedMessage.toByteString(), bytes);
+  }
+
   public void testReflectionEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -689,10 +944,11 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToEnumFieldValue().put(0, 0);
-    builder.getMutableInt32ToEnumFieldValue().put(1, 1);
-    builder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(newMap(
+            0, 0,
+            1, 1,
+            2, 1000));  // unknown value.
     TestMap message = builder.build();
 
     assertEquals(TestMap.EnumValue.FOO,
@@ -715,7 +971,7 @@
     assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
 
     // hashCode()/equals() should take unknown enum values into account.
-    builder.getMutableInt32ToEnumFieldValue().put(2, 1001);
+    builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
     TestMap message2 = builder.build();
     assertFalse(message.hashCode() == message2.hashCode());
     assertFalse(message.equals(message2));
@@ -729,15 +985,13 @@
     EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor();
     FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field");
 
-    Map<Integer, Integer> data = new HashMap<Integer, Integer>();
-    data.put(0, 0);
-    data.put(1, 1);
-    data.put(2, 1000);  // unknown value.
+    Map<Integer, Integer> data = newMap(
+        0, 0,
+        1, 1,
+        2, 1000); // unknown value
 
-    TestMap.Builder builder = TestMap.newBuilder();
-    for (Map.Entry<Integer, Integer> entry : data.entrySet()) {
-      builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue());
-    }
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(data);
 
     // Try to read unknown enum values using reflection API.
     for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) {
@@ -761,23 +1015,528 @@
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
-  
+
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToEnumFieldValue(),
+        message.getInt32ToEnumFieldValueMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValuesUsingAccessors(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  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());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(),
+        (int) testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1));
+    assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber());
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(), builder.getInt32ToEnumFieldValueOrThrow(1));
+    builder.putInt32ToEnumFieldValue(1, -1);
+    assertEquals(-1, builder.getInt32ToEnumFieldValueOrThrow(1));
+    assertEquals(TestMap.EnumValue.UNRECOGNIZED, builder.getInt32ToEnumFieldOrThrow(1));
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testReservedWordsFieldNames() {
+    ReservedAsMapField.newBuilder().build();
+    ReservedAsMapFieldWithEnumValue.newBuilder().build();
+  }
+
+  public void testDeterministicSerialziation() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    // int32->int32
+    builder.putInt32ToInt32Field(5, 1);
+    builder.putInt32ToInt32Field(1, 1);
+    builder.putInt32ToInt32Field(4, 1);
+    builder.putInt32ToInt32Field(-2, 1);
+    builder.putInt32ToInt32Field(0, 1);
+
+    // uint32->int32
+    builder.putUint32ToInt32Field(5, 1);
+    builder.putUint32ToInt32Field(1, 1);
+    builder.putUint32ToInt32Field(4, 1);
+    builder.putUint32ToInt32Field(-2, 1);
+    builder.putUint32ToInt32Field(0, 1);
+
+    // int64->int32
+    builder.putInt64ToInt32Field(5L, 1);
+    builder.putInt64ToInt32Field(1L, 1);
+    builder.putInt64ToInt32Field(4L, 1);
+    builder.putInt64ToInt32Field(-2L, 1);
+    builder.putInt64ToInt32Field(0L, 1);
+
+    // string->int32
+    builder.putStringToInt32Field("baz", 1);
+    builder.putStringToInt32Field("foo", 1);
+    builder.putStringToInt32Field("bar", 1);
+    builder.putStringToInt32Field("", 1);
+    builder.putStringToInt32Field("hello", 1);
+    builder.putStringToInt32Field("world", 1);
+
+    TestMap message = builder.build();
+    byte[] serialized = new byte[message.getSerializedSize()];
+    CodedOutputStream output = CodedOutputStream.newInstance(serialized);
+    output.useDeterministicSerialization();
+    message.writeTo(output);
+    output.flush();
+
+    CodedInputStream input = CodedInputStream.newInstance(serialized);
+    List<Integer> int32Keys = new ArrayList<Integer>();
+    List<Integer> uint32Keys = new ArrayList<Integer>();
+    List<Long> int64Keys = new ArrayList<Long>();
+    List<String> stringKeys = new ArrayList<String>();
+    int tag;
+    while (true) {
+      tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+      int length = input.readRawVarint32();
+      int oldLimit = input.pushLimit(length);
+      switch (WireFormat.getTagFieldNumber(tag)) {
+        case TestMap.STRING_TO_INT32_FIELD_FIELD_NUMBER:
+          stringKeys.add(readMapStringKey(input));
+          break;
+        case TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER:
+          int32Keys.add(readMapIntegerKey(input));
+          break;
+        case TestMap.UINT32_TO_INT32_FIELD_FIELD_NUMBER:
+          uint32Keys.add(readMapIntegerKey(input));
+          break;
+        case TestMap.INT64_TO_INT32_FIELD_FIELD_NUMBER:
+          int64Keys.add(readMapLongKey(input));
+          break;
+        default:
+          fail("Unexpected fields.");
+      }
+      input.popLimit(oldLimit);
+    }
+    assertEquals(
+        Arrays.asList(-2, 0, 1, 4, 5),
+        int32Keys);
+    assertEquals(
+        Arrays.asList(-2, 0, 1, 4, 5),
+        uint32Keys);
+    assertEquals(
+        Arrays.asList(-2L, 0L, 1L, 4L, 5L),
+        int64Keys);
+    assertEquals(
+        Arrays.asList("", "bar", "baz", "foo", "hello", "world"),
+        stringKeys);
+  }
+
+  public void testInitFromPartialDynamicMessage() {
+    FieldDescriptor fieldDescriptor =
+        TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
+    Descriptor mapEntryType = fieldDescriptor.getMessageType();
+    FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
+    FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
+    DynamicMessage dynamicMessage =
+        DynamicMessage.newBuilder(TestMap.getDescriptor())
+            .addRepeatedField(
+                fieldDescriptor,
+                DynamicMessage.newBuilder(mapEntryType)
+                    .setField(keyField, 10)
+                    .setField(valueField, TestMap.MessageValue.newBuilder().setValue(10).build())
+                    .build())
+            .build();
+    TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
+    assertEquals(
+        TestMap.MessageValue.newBuilder().setValue(10).build(),
+        message.getInt32ToMessageFieldMap().get(10));
+  }
+
+  public void testInitFromFullyDynamicMessage() {
+    FieldDescriptor fieldDescriptor =
+        TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
+    Descriptor mapEntryType = fieldDescriptor.getMessageType();
+    FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
+    FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
+    DynamicMessage dynamicMessage =
+        DynamicMessage.newBuilder(TestMap.getDescriptor())
+            .addRepeatedField(
+                fieldDescriptor,
+                DynamicMessage.newBuilder(mapEntryType)
+                    .setField(keyField, 10)
+                    .setField(
+                        valueField,
+                        DynamicMessage.newBuilder(TestMap.MessageValue.getDescriptor())
+                            .setField(
+                                TestMap.MessageValue.getDescriptor().findFieldByName("value"), 10)
+                            .build())
+                    .build())
+            .build();
+    TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
+    assertEquals(
+        TestMap.MessageValue.newBuilder().setValue(10).build(),
+        message.getInt32ToMessageFieldMap().get(10));
+  }
+
+  private int readMapIntegerKey(CodedInputStream input) throws IOException {
+    int tag = input.readTag();
+    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
+    int ret = input.readInt32();
+    // skip the value field.
+    input.skipField(input.readTag());
+    assertTrue(input.isAtEnd());
+    return ret;
+  }
+
+  private long readMapLongKey(CodedInputStream input) throws IOException {
+    int tag = input.readTag();
+    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), tag);
+    long ret = input.readInt64();
+    // skip the value field.
+    input.skipField(input.readTag());
+    assertTrue(input.isAtEnd());
+    return ret;
+  }
+
+  private String readMapStringKey(CodedInputStream input) throws IOException {
+    int tag = input.readTag();
+    assertEquals(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED), tag);
+    String ret = input.readString();
+    // skip the value field.
+    input.skipField(input.readTag());
+    assertTrue(input.isAtEnd());
+    return ret;
+  }
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
+
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    map.put(key3, value3);
+    return map;
+  }
+
+  public void testMap_withNulls() {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putStringToInt32Field(null, 3);
+      fail();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
+      fail();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      builder.putInt32ToMessageField(3, null);
+      fail();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      builder.putAllInt32ToMessageField(
+          MapTest.<Integer, MessageValue>newMap(4, null, 5, null));
+      fail();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      builder.putAllInt32ToMessageField(null);
+      fail();
+    } catch (NullPointerException expected) {
+    }
+
+    assertArrayEquals(new byte[0], builder.build().toByteArray());
+  }
 }
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 abcd3a1..4fc8f78 100644
--- a/java/core/src/test/java/com/google/protobuf/MessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java
@@ -30,15 +30,13 @@
 
 package com.google.protobuf;
 
-import protobuf_unittest.UnittestProto.TestAllTypes;
+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 protobuf_unittest.UnittestProto.ForeignMessage;
-
-import junit.framework.TestCase;
-
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Misc. unit tests for message operations that apply to both generated
@@ -76,6 +74,14 @@
       "repeated_string: \"qux\"\n" +
       "repeated_string: \"bar\"\n";
 
+  public void testParsingWithNullExtensionRegistry() throws Exception {
+    try {
+      TestAllTypes.parseFrom(new byte[] {}, null);
+      fail();
+    } catch (NullPointerException expected) {
+    }
+  }
+
   public void testMergeFrom() throws Exception {
     TestAllTypes result =
       TestAllTypes.newBuilder(MERGE_DEST)
@@ -323,8 +329,10 @@
 
     assertTrue(result.getField(result.getDescriptorForType()
         .findFieldByName("repeated_foreign_message")) instanceof List<?>);
-    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")), 0);
+    assertEquals(
+        0,
+        result.getRepeatedFieldCount(
+            result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
   }
   
   /** Test reading repeated message from DynamicMessage. */
@@ -347,7 +355,9 @@
 
     assertTrue(result.getField(result.getDescriptorForType()
         .findFieldByName("repeated_foreign_message")) instanceof List<?>);
-    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")), 2);
+    assertEquals(
+        2,
+        result.getRepeatedFieldCount(
+            result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
   }
 }
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 2365312..03ed65a 100644
--- a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
@@ -32,11 +32,9 @@
 
 import protobuf_unittest.Vehicle;
 import protobuf_unittest.Wheel;
-
-import junit.framework.TestCase;
-
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Test cases that exercise end-to-end use cases involving
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 e40a366..c388bd0 100644
--- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -32,8 +32,6 @@
 
 import static com.google.protobuf.Internal.UTF_8;
 
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
@@ -41,12 +39,14 @@
 import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link NioByteString}.
@@ -56,11 +56,12 @@
   private static final String CLASSNAME = NioByteString.class.getSimpleName();
   private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L);
   private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode();
-  private static final ByteBuffer BUFFER = ByteBuffer.wrap(BYTES.clone());
-  private static final ByteString TEST_STRING = new NioByteString(BUFFER);
+
+  private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone());
+  private final ByteString testString = new NioByteString(backingBuffer);
 
   public void testExpectedType() {
-    String actualClassName = getActualClassName(TEST_STRING);
+    String actualClassName = getActualClassName(testString);
     assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName);
   }
 
@@ -73,14 +74,14 @@
   public void testByteAt() {
     boolean stillEqual = true;
     for (int i = 0; stillEqual && i < BYTES.length; ++i) {
-      stillEqual = (BYTES[i] == TEST_STRING.byteAt(i));
+      stillEqual = (BYTES[i] == testString.byteAt(i));
     }
     assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
   }
 
   public void testByteIterator() {
     boolean stillEqual = true;
-    ByteString.ByteIterator iter = TEST_STRING.iterator();
+    ByteString.ByteIterator iter = testString.iterator();
     for (int i = 0; stillEqual && i < BYTES.length; ++i) {
       stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte());
     }
@@ -98,7 +99,7 @@
   public void testByteIterable() {
     boolean stillEqual = true;
     int j = 0;
-    for (byte quantum : TEST_STRING) {
+    for (byte quantum : testString) {
       stillEqual = (BYTES[j] == quantum);
       ++j;
     }
@@ -108,15 +109,15 @@
 
   public void testSize() {
     assertEquals(CLASSNAME + " must have the expected size", BYTES.length,
-        TEST_STRING.size());
+        testString.size());
   }
 
   public void testGetTreeDepth() {
-    assertEquals(CLASSNAME + " must have depth 0", 0, TEST_STRING.getTreeDepth());
+    assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth());
   }
 
   public void testIsBalanced() {
-    assertTrue(CLASSNAME + " is technically balanced", TEST_STRING.isBalanced());
+    assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced());
   }
 
   public void testCopyTo_ByteArrayOffsetLength() {
@@ -124,7 +125,7 @@
     int length = 100;
     byte[] destination = new byte[destinationOffset + length];
     int sourceOffset = 213;
-    TEST_STRING.copyTo(destination, sourceOffset, destinationOffset, length);
+    testString.copyTo(destination, sourceOffset, destinationOffset, length);
     boolean stillEqual = true;
     for (int i = 0; stillEqual && i < length; ++i) {
       stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset];
@@ -139,7 +140,7 @@
 
     try {
       // Copy one too many bytes
-      TEST_STRING.copyTo(destination, TEST_STRING.size() + 1 - length,
+      testString.copyTo(destination, testString.size() + 1 - length,
           destinationOffset, length);
       fail("Should have thrown an exception when copying too many bytes of a "
           + CLASSNAME);
@@ -149,7 +150,7 @@
 
     try {
       // Copy with illegal negative sourceOffset
-      TEST_STRING.copyTo(destination, -1, destinationOffset, length);
+      testString.copyTo(destination, -1, destinationOffset, length);
       fail("Should have thrown an exception when given a negative sourceOffset in "
           + CLASSNAME);
     } catch (IndexOutOfBoundsException expected) {
@@ -158,7 +159,7 @@
 
     try {
       // Copy with illegal negative destinationOffset
-      TEST_STRING.copyTo(destination, 0, -1, length);
+      testString.copyTo(destination, 0, -1, length);
       fail("Should have thrown an exception when given a negative destinationOffset in "
           + CLASSNAME);
     } catch (IndexOutOfBoundsException expected) {
@@ -167,7 +168,7 @@
 
     try {
       // Copy with illegal negative size
-      TEST_STRING.copyTo(destination, 0, 0, -1);
+      testString.copyTo(destination, 0, 0, -1);
       fail("Should have thrown an exception when given a negative size in "
           + CLASSNAME);
     } catch (IndexOutOfBoundsException expected) {
@@ -176,7 +177,7 @@
 
     try {
       // Copy with illegal too-large sourceOffset
-      TEST_STRING.copyTo(destination, 2 * TEST_STRING.size(), 0, length);
+      testString.copyTo(destination, 2 * testString.size(), 0, length);
       fail("Should have thrown an exception when the destinationOffset is too large in "
           + CLASSNAME);
     } catch (IndexOutOfBoundsException expected) {
@@ -185,7 +186,7 @@
 
     try {
       // Copy with illegal too-large destinationOffset
-      TEST_STRING.copyTo(destination, 0, 2 * destination.length, length);
+      testString.copyTo(destination, 0, 2 * destination.length, length);
       fail("Should have thrown an exception when the destinationOffset is too large in "
           + CLASSNAME);
     } catch (IndexOutOfBoundsException expected) {
@@ -196,21 +197,21 @@
   public void testCopyTo_ByteBuffer() {
     // Same length.
     ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length);
-    TEST_STRING.copyTo(myBuffer);
+    testString.copyTo(myBuffer);
     myBuffer.flip();
     assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes",
-        BUFFER, myBuffer);
+        backingBuffer, myBuffer);
 
     // Target buffer bigger than required.
-    myBuffer = ByteBuffer.allocate(TEST_STRING.size() + 1);
-    TEST_STRING.copyTo(myBuffer);
+    myBuffer = ByteBuffer.allocate(testString.size() + 1);
+    testString.copyTo(myBuffer);
     myBuffer.flip();
-    assertEquals(BUFFER, myBuffer);
+    assertEquals(backingBuffer, myBuffer);
 
     // Target buffer has no space.
     myBuffer = ByteBuffer.allocate(0);
     try {
-      TEST_STRING.copyTo(myBuffer);
+      testString.copyTo(myBuffer);
       fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
     } catch (BufferOverflowException e) {
       // Expected.
@@ -219,7 +220,7 @@
     // Target buffer too small.
     myBuffer = ByteBuffer.allocate(1);
     try {
-      TEST_STRING.copyTo(myBuffer);
+      testString.copyTo(myBuffer);
       fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
     } catch (BufferOverflowException e) {
       // Expected.
@@ -227,26 +228,26 @@
   }
 
   public void testMarkSupported() {
-    InputStream stream = TEST_STRING.newInput();
+    InputStream stream = testString.newInput();
     assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
   }
 
   public void testMarkAndReset() throws IOException {
-    int fraction = TEST_STRING.size() / 3;
+    int fraction = testString.size() / 3;
 
-    InputStream stream = TEST_STRING.newInput();
-    stream.mark(TEST_STRING.size()); // First, mark() the end.
+    InputStream stream = testString.newInput();
+    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",
-        (TEST_STRING.size() - fraction), stream.available());
+        (testString.size() - fraction), stream.available());
     stream.reset();
     assertEquals(
         CLASSNAME + ": after resetting, all bytes are available",
-        TEST_STRING.size(), stream.available());
+        testString.size(), stream.available());
 
-    skipFully(stream, TEST_STRING.size()); // Skip to the end.
+    skipFully(stream, testString.size()); // Skip to the end.
     assertEquals(
         CLASSNAME + ": after skipping to the end, no more bytes are available",
         0, stream.available());
@@ -284,7 +285,7 @@
   }
 
   public void testAsReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer = TEST_STRING.asReadOnlyByteBuffer();
+    ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer();
     byte[] roundTripBytes = new byte[BYTES.length];
     assertTrue(byteBuffer.remaining() == BYTES.length);
     assertTrue(byteBuffer.isReadOnly());
@@ -294,7 +295,7 @@
   }
 
   public void testAsReadOnlyByteBufferList() {
-    List<ByteBuffer> byteBuffers = TEST_STRING.asReadOnlyByteBufferList();
+    List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList();
     int bytesSeen = 0;
     byte[] roundTripBytes = new byte[BYTES.length];
     for (ByteBuffer byteBuffer : byteBuffers) {
@@ -310,25 +311,98 @@
   }
 
   public void testToByteArray() {
-    byte[] roundTripBytes = TEST_STRING.toByteArray();
+    byte[] roundTripBytes = testString.toByteArray();
     assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes",
         Arrays.equals(BYTES, roundTripBytes));
   }
 
   public void testWriteTo() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    TEST_STRING.writeTo(bos);
+    testString.writeTo(bos);
     byte[] roundTripBytes = bos.toByteArray();
     assertTrue(CLASSNAME + ".writeTo() must give back the same bytes",
         Arrays.equals(BYTES, roundTripBytes));
   }
 
+  public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    byte[] original = Arrays.copyOf(BYTES, BYTES.length);
+    testString.writeTo(os);
+    assertTrue(CLASSNAME + ".writeTo() must NOT grant access to underlying buffer",
+        Arrays.equals(original, BYTES));
+  }
+
+  public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    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()));
+  }
+
+  public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+    ByteOutput out = new ByteOutput() {
+      @Override
+      public void write(byte value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(ByteBuffer value) throws IOException {
+        Arrays.fill(value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(),
+            (byte) 0);
+      }
+    };
+
+    testString.writeTo(out);
+    byte[] allZeros = new byte[testString.size()];
+    assertTrue(CLASSNAME + ".writeTo() must grant access to underlying buffer",
+        Arrays.equals(allZeros, backingBuffer.array()));
+  }
+
   public void testNewOutput() throws IOException {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     ByteString.Output output = ByteString.newOutput();
-    TEST_STRING.writeTo(output);
+    testString.writeTo(output);
     assertEquals("Output Size returns correct result",
-        output.size(), TEST_STRING.size());
+        output.size(), testString.size());
     output.writeTo(bos);
     assertTrue("Output.writeTo() must give back the same bytes",
         Arrays.equals(BYTES, bos.toByteArray()));
@@ -336,7 +410,7 @@
     // write the output stream to itself! This should cause it to double
     output.writeTo(output);
     assertEquals("Writing an output stream to itself is successful",
-        TEST_STRING.concat(TEST_STRING), output.toByteString());
+        testString.concat(testString), output.toByteString());
 
     output.reset();
     assertEquals("Output.reset() resets the output", 0, output.size());
@@ -373,7 +447,7 @@
     }
 
     try {
-      TEST_STRING.toString("invalid");
+      testString.toString("invalid");
       fail("Should have thrown an exception.");
     } catch (UnsupportedEncodingException expected) {
       // This is success
@@ -381,36 +455,36 @@
   }
 
   public void testEquals() {
-    assertEquals(CLASSNAME + " must not equal null", false, TEST_STRING.equals(null));
-    assertEquals(CLASSNAME + " must equal self", TEST_STRING, TEST_STRING);
+    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",
-        TEST_STRING.equals(EMPTY));
+        testString.equals(EMPTY));
     assertEquals(CLASSNAME + " empty strings must be equal",
-        EMPTY, TEST_STRING.substring(55, 55));
+        EMPTY, testString.substring(55, 55));
     assertEquals(CLASSNAME + " must equal another string with the same value",
-        TEST_STRING, new NioByteString(BUFFER));
+        testString, new NioByteString(backingBuffer));
 
     byte[] mungedBytes = mungedBytes();
     assertFalse(CLASSNAME + " must not equal every string with the same length",
-        TEST_STRING.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+        testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
   }
 
   public void testEqualsLiteralByteString() {
     ByteString literal = ByteString.copyFrom(BYTES);
     assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal,
-        TEST_STRING);
-    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", TEST_STRING,
+        testString);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString,
         literal);
     assertFalse(CLASSNAME + " must not equal the empty string",
-        TEST_STRING.equals(ByteString.EMPTY));
+        testString.equals(ByteString.EMPTY));
     assertEquals(CLASSNAME + " empty strings must be equal",
-        ByteString.EMPTY, TEST_STRING.substring(55, 55));
+        ByteString.EMPTY, testString.substring(55, 55));
 
     literal = ByteString.copyFrom(mungedBytes());
     assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
-        TEST_STRING.equals(literal));
+        testString.equals(literal));
     assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
-        literal.equals(TEST_STRING));
+        literal.equals(testString));
   }
 
   public void testEqualsRopeByteString() {
@@ -419,22 +493,22 @@
     ByteString rope = p1.concat(p2);
 
     assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope,
-        TEST_STRING);
-    assertEquals(CLASSNAME + " must equal RopeByteString with same value", TEST_STRING,
+        testString);
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString,
         rope);
     assertFalse(CLASSNAME + " must not equal the empty string",
-        TEST_STRING.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
+        testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
     assertEquals(CLASSNAME + " empty strings must be equal",
-        ByteString.EMPTY.concat(ByteString.EMPTY), TEST_STRING.substring(55, 55));
+        ByteString.EMPTY.concat(ByteString.EMPTY), 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",
-        TEST_STRING.equals(rope));
+        testString.equals(rope));
     assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
-        rope.equals(TEST_STRING));
+        rope.equals(testString));
   }
 
   private byte[] mungedBytes() {
@@ -445,12 +519,12 @@
   }
 
   public void testHashCode() {
-    int hash = TEST_STRING.hashCode();
+    int hash = testString.hashCode();
     assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
   }
 
   public void testPeekCachedHashCode() {
-    ByteString newString = new NioByteString(BUFFER);
+    ByteString newString = new NioByteString(backingBuffer);
     assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0,
         newString.peekCachedHashCode());
     newString.hashCode();
@@ -461,15 +535,15 @@
   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 = TEST_STRING.partialHash(TEST_STRING.size(), 0, TEST_STRING.size());
+    int hash = testString.partialHash(testString.size(), 0, testString.size());
     assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode",
         EXPECTED_HASH, hash);
   }
 
   public void testNewInput() throws IOException {
-    InputStream input = TEST_STRING.newInput();
+    InputStream input = testString.newInput();
     assertEquals("InputStream.available() returns correct value",
-        TEST_STRING.size(), input.available());
+        testString.size(), input.available());
     boolean stillEqual = true;
     for (byte referenceByte : BYTES) {
       int expectedInt = (referenceByte & 0xFF);
@@ -482,8 +556,8 @@
   }
 
   public void testNewInput_skip() throws IOException {
-    InputStream input = TEST_STRING.newInput();
-    int stringSize = TEST_STRING.size();
+    InputStream input = testString.newInput();
+    int stringSize = testString.size();
     int nearEndIndex = stringSize * 2 / 3;
     long skipped1 = input.skip(nearEndIndex);
     assertEquals("InputStream.skip()", skipped1, nearEndIndex);
@@ -492,7 +566,7 @@
     assertTrue("InputStream.mark() is available", input.markSupported());
     input.mark(0);
     assertEquals("InputStream.skip(), read()",
-        TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+        testString.byteAt(nearEndIndex) & 0xFF, input.read());
     assertEquals("InputStream.available()",
         stringSize - skipped1 - 1, input.available());
     long skipped2 = input.skip(stringSize);
@@ -504,11 +578,11 @@
     assertEquals("InputStream.reset() succeded",
         stringSize - skipped1, input.available());
     assertEquals("InputStream.reset(), read()",
-        TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+        testString.byteAt(nearEndIndex) & 0xFF, input.read());
   }
 
   public void testNewCodedInput() throws IOException {
-    CodedInputStream cis = TEST_STRING.newCodedInput();
+    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));
@@ -521,22 +595,22 @@
    */
   public void testConcat_empty() {
     assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME,
-        TEST_STRING.concat(EMPTY), TEST_STRING);
+        testString.concat(EMPTY), testString);
     assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
-        EMPTY.concat(TEST_STRING), TEST_STRING);
+        EMPTY.concat(testString), testString);
   }
 
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
-    oos.writeObject(TEST_STRING);
+    oos.writeObject(testString);
     oos.close();
     byte[] pickled = out.toByteArray();
     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", TEST_STRING, o);
+    assertEquals("Should get an equal ByteString back", testString, o);
   }
 
   private static ByteString forString(String str) {
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 37fa242..e376b1c 100644
--- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -1,5 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 package com.google.protobuf;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import com.google.protobuf.DescriptorProtos.DescriptorProto;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -7,11 +42,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser}
@@ -22,6 +54,7 @@
  *
  * @author jh@squareup.com (Joshua Humphries)
  */
+@RunWith(JUnit4.class)
 public class ParseExceptionsTest {
 
   private interface ParseTester {
@@ -46,116 +79,143 @@
 
   @Test public void message_parseFrom_InputStream() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseFrom(in);
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(in);
+          }
+        });
   }
 
   @Test public void message_parseFrom_InputStreamAndExtensionRegistry() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
+          }
+        });
   }
 
   @Test public void message_parseFrom_CodedInputStream() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
+          }
+        });
   }
 
   @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseFrom(CodedInputStream.newInstance(in),
-            ExtensionRegistry.newInstance());
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(
+                CodedInputStream.newInstance(in), ExtensionRegistry.newInstance());
+          }
+        });
   }
 
   @Test public void message_parseDelimitedFrom_InputStream() {
     setupDelimited();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseDelimitedFrom(in);
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseDelimitedFrom(in);
+          }
+        });
   }
 
   @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() {
     setupDelimited();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeFrom_InputStream() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.newBuilder().mergeFrom(in).build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder().mergeFrom(in).build();
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.newBuilder().mergeFrom(in, ExtensionRegistry.newInstance()).build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder()
+                .mergeFrom(in, ExtensionRegistry.newInstance())
+                .build();
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeFrom_CodedInputStream() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() {
     setup();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        return DescriptorProto.newBuilder()
-            .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()).build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder()
+                .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance())
+                .build();
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeDelimitedFrom_InputStream() {
     setupDelimited();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        DescriptorProto.Builder builder = DescriptorProto.newBuilder();
-        builder.mergeDelimitedFrom(in);
-        return builder.build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+            builder.mergeDelimitedFrom(in);
+            return builder.build();
+          }
+        });
   }
 
   @Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() {
     setupDelimited();
-    verifyExceptions(new ParseTester() {
-      public DescriptorProto parse(InputStream in) throws IOException {
-        DescriptorProto.Builder builder = DescriptorProto.newBuilder();
-        builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
-        return builder.build();
-      }
-    });
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+            builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
+            return builder.build();
+          }
+        });
   }
 
   private void verifyExceptions(ParseTester parseTester) {
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 5a92bac..1e89111 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -30,25 +30,21 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-import com.google.protobuf.UnittestLite.TestParsingMergeLite;
+import protobuf_unittest.UnittestOptimizeFor;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor;
+import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestParsingMerge;
 import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InterruptedIOException;
+import junit.framework.TestCase;
 
 /**
  * Unit test for {@link Parser}.
@@ -80,6 +76,8 @@
         new ByteArrayInputStream(data), registry));
     assertMessageEquals(message, parser.parseFrom(
         CodedInputStream.newInstance(data), registry));
+    assertMessageEquals(
+        message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
   }
 
   @SuppressWarnings("unchecked")
@@ -100,6 +98,7 @@
         new ByteArrayInputStream(data)));
     assertMessageEquals(message, parser.parseFrom(
         CodedInputStream.newInstance(data)));
+    assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
   }
 
   private void assertMessageEquals(
@@ -179,16 +178,12 @@
   public void testParseExtensions() throws Exception {
     assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
                           TestUtil.getExtensionRegistry());
-    assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(),
-                          TestUtil.getExtensionRegistryLite());
   }
 
   public void testParsePacked() throws Exception {
     assertRoundTripEquals(TestUtil.getPackedSet());
     assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
                           TestUtil.getExtensionRegistry());
-    assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(),
-                          TestUtil.getExtensionRegistryLite());
   }
 
   public void testParseDelimitedTo() throws Exception {
@@ -196,20 +191,11 @@
     TestAllTypes normalMessage = TestUtil.getAllSet();
     ByteArrayOutputStream output = new ByteArrayOutputStream();
     normalMessage.writeDelimitedTo(output);
-
-    // Write MessageLite with packed extension fields.
-    TestPackedExtensionsLite packedMessage =
-        TestUtil.getLitePackedExtensionsSet();
-    packedMessage.writeDelimitedTo(output);
+    normalMessage.writeDelimitedTo(output);
 
     InputStream input = new ByteArrayInputStream(output.toByteArray());
-    assertMessageEquals(
-        normalMessage,
-        normalMessage.getParserForType().parseDelimitedFrom(input));
-    assertMessageEquals(
-        packedMessage,
-        packedMessage.getParserForType().parseDelimitedFrom(
-            input, TestUtil.getExtensionRegistryLite()));
+    assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
+    assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
   }
 
   public void testParseUnknownFields() throws Exception {
@@ -244,14 +230,6 @@
     assertEquals("hello", allTypes.getOptionalString());
   }
 
-  /** Helper method for {@link #testParsingMergeLite()}.*/
-  private void assertMessageMerged(TestAllTypesLite allTypes)
-      throws Exception {
-    assertEquals(3, allTypes.getOptionalInt32());
-    assertEquals(2, allTypes.getOptionalInt64());
-    assertEquals("hello", allTypes.getOptionalString());
-  }
-
   public void testParsingMerge() throws Exception {
     // Build messages.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -313,65 +291,42 @@
         TestParsingMerge.repeatedExt));
   }
 
-  public void testParsingMergeLite() throws Exception {
-    // Build messages.
-    TestAllTypesLite.Builder builder =
-        TestAllTypesLite.newBuilder();
-    TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
-    builder.clear();
-    TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
-    builder.clear();
-    TestAllTypesLite msg3 = builder.setOptionalInt32(3)
-        .setOptionalString("hello").build();
+  public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
+    try {
+      TestUtil.getAllSet().parseDelimitedFrom(
+          new InputStream() {
+            @Override
+            public int read() throws IOException {
+              throw new InterruptedIOException();
+            }
+          });
+      fail("Expected InterruptedIOException");
+    } catch (Exception e) {
+      assertEquals(InterruptedIOException.class, e.getClass());
+    }
+  }
 
-    // Build groups.
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg3).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg3).build();
+  public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
+    try {
+      TestUtil.getAllSet().parseDelimitedFrom(
+          new InputStream() {
+            private int i;
 
-    // Assign and serialize RepeatedFieldsGenerator.
-    ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
-        .addField1(msg1).addField1(msg2).addField1(msg3)
-        .addField2(msg1).addField2(msg2).addField2(msg3)
-        .addField3(msg1).addField3(msg2).addField3(msg3)
-        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
-        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
-        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
-        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
-        .build().toByteString();
-
-    // Parse TestParsingMergeLite.
-    ExtensionRegistry registry = ExtensionRegistry.newInstance();
-    UnittestLite.registerAllExtensions(registry);
-    TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry);
-
-    // Required and optional fields should be merged.
-    assertMessageMerged(parsingMerge.getRequiredAllTypes());
-    assertMessageMerged(parsingMerge.getOptionalAllTypes());
-    assertMessageMerged(
-        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
-    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));
+            @Override
+            public int read() throws IOException {
+              switch (i++) {
+                case 0:
+                  return 1;
+                case 1:
+                  throw new InterruptedIOException();
+                default:
+                  throw new AssertionError();
+              }
+            }
+          });
+      fail("Expected InterruptedIOException");
+    } catch (Exception e) {
+      assertEquals(InterruptedIOException.class, e.getClass());
+    }
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
index 245c3de..af717bf 100644
--- a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -32,12 +32,11 @@
 
 import static java.util.Arrays.asList;
 
-import junit.framework.TestCase;
-
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link ProtobufArrayList}.
@@ -63,20 +62,6 @@
     assertImmutable(ProtobufArrayList.<Integer>emptyList());
   }
   
-  public void testCopyConstructor() {
-    ProtobufArrayList<Integer> copy = new ProtobufArrayList<Integer>(TERTIARY_LIST);
-    assertEquals(TERTIARY_LIST, copy);
-
-    copy = new ProtobufArrayList<Integer>(IntArrayList.emptyList());
-    assertEquals(ProtobufArrayList.emptyList(), copy);
-    
-    copy = new ProtobufArrayList<Integer>(asList(1, 2, 3));
-    assertEquals(asList(1, 2, 3), copy);
-
-    copy = new ProtobufArrayList<Integer>(Collections.<Integer>emptyList());
-    assertEquals(ProtobufArrayList.emptyList(), copy);
-  }
-  
   public void testModificationWithIteration() {
     list.addAll(asList(1, 2, 3, 4));
     Iterator<Integer> iterator = list.iterator();
diff --git a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
similarity index 91%
rename from java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
index 49d5232..edbd0af 100644
--- a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
+++ b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
@@ -32,25 +32,23 @@
 
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-
-import junit.framework.TestCase;
-
 import java.util.Collections;
 import java.util.List;
+import junit.framework.TestCase;
 
 /**
- * Tests for {@link RepeatedFieldBuilder}. This tests basic functionality.
+ * Tests for {@link RepeatedFieldBuilderV3}. This tests basic functionality.
  * More extensive testing is provided via other tests that exercise the
  * builder.
  *
  * @author jonp@google.com (Jon Perlow)
  */
-public class RepeatedFieldBuilderTest extends TestCase {
+public class RepeatedFieldBuilderV3Test extends TestCase {
 
   public void testBasicUse() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
+    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());
@@ -70,8 +68,8 @@
 
   public void testGoingBackAndForth() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
+    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());
@@ -99,8 +97,8 @@
 
   public void testVariousMethods() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build());
     builder.addBuilder(0, TestAllTypes.getDefaultInstance())
@@ -141,8 +139,8 @@
 
   public void testLists() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
     builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
     builder.addMessage(0,
         TestAllTypes.newBuilder().setOptionalInt32(0).build());
@@ -180,10 +178,10 @@
     }
   }
 
-  private RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+  private RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
       TestAllTypesOrBuilder>
-      newRepeatedFieldBuilder(GeneratedMessage.BuilderParent parent) {
-    return new RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+      newRepeatedFieldBuilderV3(GeneratedMessage.BuilderParent parent) {
+    return new RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
         TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false,
         parent, false);
   }
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 ff980d6..b895ad8 100644
--- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -35,21 +35,19 @@
 import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
 import protobuf_unittest.MessageWithNoOuter;
 import protobuf_unittest.ServiceWithNoOuter;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestService;
-import protobuf_unittest.UnittestProto.FooRequest;
-import protobuf_unittest.UnittestProto.FooResponse;
 import protobuf_unittest.UnittestProto.BarRequest;
 import protobuf_unittest.UnittestProto.BarResponse;
-
-import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
-import org.easymock.IArgumentMatcher;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestService;
 
 import java.util.HashSet;
 import java.util.Set;
-
 import junit.framework.TestCase;
+import org.easymock.classextension.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.IMocksControl;
 
 /**
  * Tests services and stubs.
@@ -175,12 +173,14 @@
     MethodDescriptor fooMethod =
         ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
-    RpcCallback<Message> callback = new RpcCallback<Message>() {
-      public void run(Message parameter) {
-        // No reason this should be run.
-        fail();
-      }
-    };
+    RpcCallback<Message> callback =
+        new RpcCallback<Message>() {
+          @Override
+          public void run(Message parameter) {
+            // No reason this should be run.
+            fail();
+          }
+        };
     RpcCallback<TestAllTypes> specializedCallback =
         RpcUtil.specializeCallback(callback);
 
@@ -269,6 +269,8 @@
         file.getServices().get(0).getMethods().get(0).getName());
   }
 
+
+
   // =================================================================
 
   /**
@@ -290,7 +292,9 @@
     public boolean isCalled() { return called; }
 
     public void reset() { called = false; }
-    public void run(Type message) { called = true; }
+    @Override
+    public void run(Type message) {
+      called = true; }
   }
 
   /** Implementation of the wrapsCallback() argument matcher. */
@@ -301,6 +305,7 @@
       this.callback = callback;
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public boolean matches(Object actual) {
       if (!(actual instanceof RpcCallback)) {
@@ -313,6 +318,7 @@
       return callback.isCalled();
     }
 
+    @Override
     public void appendTo(StringBuffer buffer) {
       buffer.append("wrapsCallback(mockCallback)");
     }
diff --git a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
similarity index 89%
rename from java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
index 58b8000..e3a8d4f 100644
--- a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
+++ b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
@@ -36,19 +36,19 @@
 import junit.framework.TestCase;
 
 /**
- * Tests for {@link SingleFieldBuilder}. This tests basic functionality.
+ * Tests for {@link SingleFieldBuilderV3}. This tests basic functionality.
  * More extensive testing is provided via other tests that exercise the
  * builder.
  *
  * @author jonp@google.com (Jon Perlow)
  */
-public class SingleFieldBuilderTest extends TestCase {
+public class SingleFieldBuilderV3Test extends TestCase {
 
   public void testBasicUseAndInvalidations() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
         TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
             TestAllTypesOrBuilder>(
             TestAllTypes.getDefaultInstance(),
             mockParent,
@@ -76,9 +76,9 @@
 
   public void testSetMessage() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
         TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
             TestAllTypesOrBuilder>(
             TestAllTypes.getDefaultInstance(),
             mockParent,
@@ -102,9 +102,9 @@
 
   public void testClear() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
         TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
             TestAllTypesOrBuilder>(
             TestAllTypes.getDefaultInstance(),
             mockParent,
@@ -122,9 +122,9 @@
 
   public void testMerge() {
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
         TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
             TestAllTypesOrBuilder>(
             TestAllTypes.getDefaultInstance(),
             mockParent,
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 366086d..a7f8342 100644
--- a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
@@ -30,8 +30,6 @@
 
 package com.google.protobuf;
 
-import junit.framework.TestCase;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -40,6 +38,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import junit.framework.TestCase;
 
 /**
  * @author darick@google.com Darick Tong
@@ -56,14 +55,17 @@
       this.value = value;
     }
 
+    @Override
     public K getKey() {
       return key;
     }
 
+    @Override
     public V getValue() {
       return value;
     }
 
+    @Override
     public V setValue(V value) {
       V oldValue = this.value;
       this.value = value;
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
index 2c60fe0..4af5542 100644
--- a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
@@ -92,5 +92,31 @@
     assertEquals(0L, message.getExtension(
         TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
 
+    assertEquals("", message.getFieldName32());
+    assertEquals("", message.getFieldName33());
+    assertEquals(0, message.get2Conflict34());
+    assertEquals(0, message.get2Conflict35());
+
+  }
+
+  public void testNumberFields() throws Exception {
+    TestBadIdentifiersProto.TestLeadingNumberFields message =
+        TestBadIdentifiersProto.TestLeadingNumberFields.getDefaultInstance();
+    // Make sure generated accessors are properly named.
+    assertFalse(message.has30DayImpressions());
+    assertEquals(0, message.get30DayImpressions());
+    assertEquals(0, message.get60DayImpressionsCount());
+    assertEquals(0, message.get60DayImpressionsList().size());
+
+    assertFalse(message.has2Underscores());
+    assertEquals("", message.get2Underscores());
+    assertEquals(0, message.get2RepeatedUnderscoresCount());
+    assertEquals(0, message.get2RepeatedUnderscoresList().size());
+
+    assertFalse(message.has32());
+    assertEquals(0, message.get32());
+    assertEquals(0, message.get64Count());
+    assertEquals(0, message.get64List().size());
+
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
new file mode 100644
index 0000000..37f94c0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
@@ -0,0 +1,83 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that proto2 api generation doesn't cause compile errors when compiling protocol buffers
+ * that have names that would otherwise conflict if not fully qualified (like @Deprecated
+ * and @Override).
+ *
+ * <p>Forked from {@link TestBadIdentifiers}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public final class TestBadIdentifiersLite extends TestCase {
+
+  public void testCompilation() {
+    // If this compiles, it means the generation was correct.
+    TestBadIdentifiersProto.Deprecated.newBuilder();
+    TestBadIdentifiersProto.Override.newBuilder();
+  }
+
+  public void testConflictingFieldNames() throws Exception {
+    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());
+
+    assertEquals(0, message.getInt32FieldCount11());
+    assertEquals(0, message.getEnumFieldCount12().getNumber());
+    assertEquals("", message.getStringFieldCount13());
+    assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
+    assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+
+    assertEquals(0, message.getInt32Field21Count());
+    assertEquals(0, message.getEnumField22Count());
+    assertEquals(0, message.getStringField23Count());
+    assertEquals(0, message.getBytesField24Count());
+    assertEquals(0, message.getMessageField25Count());
+
+    assertEquals(0, message.getInt32Field1List().size());
+    assertEquals(0, message.getInt32FieldList31());
+
+    assertEquals(0, message.getInt64FieldCount());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+  }
+}
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 01acb88..b4bc3a3 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -30,205 +30,200 @@
 
 package com.google.protobuf;
 
-import protobuf_unittest.UnittestProto;
-import com.google.protobuf.UnittestLite;
-
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
+import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultBytesExtension;
+import static protobuf_unittest.UnittestProto.defaultCordExtension;
+import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
+import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultFloatExtension;
+import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
 // The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
 // import static protobuf_unittest.UnittestProto.*;
 import static protobuf_unittest.UnittestProto.defaultInt32Extension;
 import static protobuf_unittest.UnittestProto.defaultInt64Extension;
-import static protobuf_unittest.UnittestProto.defaultUint32Extension;
-import static protobuf_unittest.UnittestProto.defaultUint64Extension;
-import static protobuf_unittest.UnittestProto.defaultSint32Extension;
-import static protobuf_unittest.UnittestProto.defaultSint64Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
 import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
-import static protobuf_unittest.UnittestProto.defaultFloatExtension;
-import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
-import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultSint32Extension;
+import static protobuf_unittest.UnittestProto.defaultSint64Extension;
 import static protobuf_unittest.UnittestProto.defaultStringExtension;
-import static protobuf_unittest.UnittestProto.defaultBytesExtension;
-import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
-import static protobuf_unittest.UnittestProto.defaultCordExtension;
-
-import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint64Extension;
+import static protobuf_unittest.UnittestProto.oneofBytesExtension;
 import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
 import static protobuf_unittest.UnittestProto.oneofStringExtension;
-import static protobuf_unittest.UnittestProto.oneofBytesExtension;
-
-import static protobuf_unittest.UnittestProto.optionalInt32Extension;
-import static protobuf_unittest.UnittestProto.optionalInt64Extension;
-import static protobuf_unittest.UnittestProto.optionalUint32Extension;
-import static protobuf_unittest.UnittestProto.optionalUint64Extension;
-import static protobuf_unittest.UnittestProto.optionalSint32Extension;
-import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalBoolExtension;
+import static protobuf_unittest.UnittestProto.optionalBytesExtension;
+import static protobuf_unittest.UnittestProto.optionalCordExtension;
+import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
 import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
 import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
 import static protobuf_unittest.UnittestProto.optionalFloatExtension;
-import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
-import static protobuf_unittest.UnittestProto.optionalBoolExtension;
-import static protobuf_unittest.UnittestProto.optionalStringExtension;
-import static protobuf_unittest.UnittestProto.optionalBytesExtension;
-import static protobuf_unittest.UnittestProto.optionalGroupExtension;
-import static protobuf_unittest.UnittestProto.optionalCordExtension;
 import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
 import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalGroupExtension;
 import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
 import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
 import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
 import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
 import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalSint32Extension;
+import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalStringExtension;
 import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
-
-import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
-import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
-import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
-import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
-import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
-import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
-import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
-import static protobuf_unittest.UnittestProto.repeatedStringExtension;
-import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
-import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
-import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
-import static protobuf_unittest.UnittestProto.repeatedCordExtension;
-
-import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
-import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
-
-import static protobuf_unittest.UnittestProto.packedInt32Extension;
-import static protobuf_unittest.UnittestProto.packedInt64Extension;
-import static protobuf_unittest.UnittestProto.packedUint32Extension;
-import static protobuf_unittest.UnittestProto.packedUint64Extension;
-import static protobuf_unittest.UnittestProto.packedSint32Extension;
-import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalUint64Extension;
+import static protobuf_unittest.UnittestProto.packedBoolExtension;
+import static protobuf_unittest.UnittestProto.packedDoubleExtension;
+import static protobuf_unittest.UnittestProto.packedEnumExtension;
 import static protobuf_unittest.UnittestProto.packedFixed32Extension;
 import static protobuf_unittest.UnittestProto.packedFixed64Extension;
+import static protobuf_unittest.UnittestProto.packedFloatExtension;
+import static protobuf_unittest.UnittestProto.packedInt32Extension;
+import static protobuf_unittest.UnittestProto.packedInt64Extension;
 import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
 import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
-import static protobuf_unittest.UnittestProto.packedFloatExtension;
-import static protobuf_unittest.UnittestProto.packedDoubleExtension;
-import static protobuf_unittest.UnittestProto.packedBoolExtension;
-import static protobuf_unittest.UnittestProto.packedEnumExtension;
+import static protobuf_unittest.UnittestProto.packedSint32Extension;
+import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.packedUint32Extension;
+import static protobuf_unittest.UnittestProto.packedUint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
+import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
+import static protobuf_unittest.UnittestProto.repeatedCordExtension;
+import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
+import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
+import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
+import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedStringExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
+import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
 
-import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
-
-import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
-import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
-
-import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
-
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
 import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -236,28 +231,12 @@
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import com.google.protobuf.test.UnittestImport.ImportEnum;
-import com.google.protobuf.test.UnittestImport.ImportMessage;
-import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
-
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-import com.google.protobuf.UnittestLite.ForeignMessageLite;
-import com.google.protobuf.UnittestLite.ForeignEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportMessageLite;
-import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
-
-import junit.framework.Assert;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import junit.framework.Assert;
 
 /**
  * Contains methods for setting all fields of {@code TestAllTypes} to
@@ -274,12 +253,24 @@
 public final class TestUtil {
   private TestUtil() {}
 
+  public static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+      TestRequired.newBuilder().setA(1).buildPartial();
+  public static final TestRequired TEST_REQUIRED_INITIALIZED =
+      TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
   /** Helper to convert a String to ByteString. */
   static ByteString toBytes(String str) {
     return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
   }
 
   /**
+   * Dirties the message by resetting the momoized serialized size.
+   */
+  public static void resetMemoizedSize(AbstractMessage message) {
+    message.memoizedSize = -1;
+  }
+
+  /**
    * Get a {@code TestAllTypes} with all fields set as they would be by
    * {@link #setAllFields(TestAllTypes.Builder)}.
    */
@@ -300,16 +291,6 @@
   }
 
   /**
-   * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
-   * {@link #setAllFields(TestAllTypesLite.Builder)}.
-   */
-  public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
-    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
-    setAllFields(builder);
-    return builder;
-  }
-
-  /**
    * Get a {@code TestAllExtensions} with all fields set as they would be by
    * {@link #setAllExtensions(TestAllExtensions.Builder)}.
    */
@@ -319,12 +300,6 @@
     return builder.build();
   }
 
-  public static TestAllExtensionsLite getAllLiteExtensionsSet() {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    setAllExtensions(builder);
-    return builder.build();
-  }
-
   public static TestPackedTypes getPackedSet() {
     TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
     setPackedFields(builder);
@@ -343,157 +318,6 @@
     return builder.build();
   }
 
-  public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
-    TestPackedExtensionsLite.Builder builder =
-        TestPackedExtensionsLite.newBuilder();
-    setPackedExtensions(builder);
-    return builder.build();
-  }
-  
-  /**
-   * Set every field of {@code builder} to the values expected by
-   * {@code assertAllFieldsSet()}.
-   */
-  public static void setAllFields(TestAllTypesLite.Builder builder) {
-    builder.setOptionalInt32   (101);
-    builder.setOptionalInt64   (102);
-    builder.setOptionalUint32  (103);
-    builder.setOptionalUint64  (104);
-    builder.setOptionalSint32  (105);
-    builder.setOptionalSint64  (106);
-    builder.setOptionalFixed32 (107);
-    builder.setOptionalFixed64 (108);
-    builder.setOptionalSfixed32(109);
-    builder.setOptionalSfixed64(110);
-    builder.setOptionalFloat   (111);
-    builder.setOptionalDouble  (112);
-    builder.setOptionalBool    (true);
-    builder.setOptionalString  ("115");
-    builder.setOptionalBytes   (toBytes("116"));
-
-    builder.setOptionalGroup(
-        TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
-    builder.setOptionalNestedMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
-    builder.setOptionalForeignMessage(
-        ForeignMessageLite.newBuilder().setC(119).build());
-    builder.setOptionalImportMessage(
-        ImportMessageLite.newBuilder().setD(120).build());
-    builder.setOptionalPublicImportMessage(
-        PublicImportMessageLite.newBuilder().setE(126).build());
-    builder.setOptionalLazyMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
-
-    builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
-    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
-    builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
-
-    builder.setOptionalStringPiece("124");
-    builder.setOptionalCord("125");
-
-    // -----------------------------------------------------------------
-
-    builder.addRepeatedInt32   (201);
-    builder.addRepeatedInt64   (202);
-    builder.addRepeatedUint32  (203);
-    builder.addRepeatedUint64  (204);
-    builder.addRepeatedSint32  (205);
-    builder.addRepeatedSint64  (206);
-    builder.addRepeatedFixed32 (207);
-    builder.addRepeatedFixed64 (208);
-    builder.addRepeatedSfixed32(209);
-    builder.addRepeatedSfixed64(210);
-    builder.addRepeatedFloat   (211);
-    builder.addRepeatedDouble  (212);
-    builder.addRepeatedBool    (true);
-    builder.addRepeatedString  ("215");
-    builder.addRepeatedBytes   (toBytes("216"));
-
-    builder.addRepeatedGroup(
-        TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
-    builder.addRepeatedNestedMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
-    builder.addRepeatedForeignMessage(
-        ForeignMessageLite.newBuilder().setC(219).build());
-    builder.addRepeatedImportMessage(
-        ImportMessageLite.newBuilder().setD(220).build());
-    builder.addRepeatedLazyMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
-
-    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
-    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
-    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
-
-    builder.addRepeatedStringPiece("224");
-    builder.addRepeatedCord("225");
-
-    // Add a second one of each field.
-    builder.addRepeatedInt32   (301);
-    builder.addRepeatedInt64   (302);
-    builder.addRepeatedUint32  (303);
-    builder.addRepeatedUint64  (304);
-    builder.addRepeatedSint32  (305);
-    builder.addRepeatedSint64  (306);
-    builder.addRepeatedFixed32 (307);
-    builder.addRepeatedFixed64 (308);
-    builder.addRepeatedSfixed32(309);
-    builder.addRepeatedSfixed64(310);
-    builder.addRepeatedFloat   (311);
-    builder.addRepeatedDouble  (312);
-    builder.addRepeatedBool    (false);
-    builder.addRepeatedString  ("315");
-    builder.addRepeatedBytes   (toBytes("316"));
-
-    builder.addRepeatedGroup(
-        TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
-    builder.addRepeatedNestedMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
-    builder.addRepeatedForeignMessage(
-        ForeignMessageLite.newBuilder().setC(319).build());
-    builder.addRepeatedImportMessage(
-        ImportMessageLite.newBuilder().setD(320).build());
-    builder.addRepeatedLazyMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
-
-    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
-    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
-    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
-
-    builder.addRepeatedStringPiece("324");
-    builder.addRepeatedCord("325");
-
-    // -----------------------------------------------------------------
-
-    builder.setDefaultInt32   (401);
-    builder.setDefaultInt64   (402);
-    builder.setDefaultUint32  (403);
-    builder.setDefaultUint64  (404);
-    builder.setDefaultSint32  (405);
-    builder.setDefaultSint64  (406);
-    builder.setDefaultFixed32 (407);
-    builder.setDefaultFixed64 (408);
-    builder.setDefaultSfixed32(409);
-    builder.setDefaultSfixed64(410);
-    builder.setDefaultFloat   (411);
-    builder.setDefaultDouble  (412);
-    builder.setDefaultBool    (false);
-    builder.setDefaultString  ("415");
-    builder.setDefaultBytes   (toBytes("416"));
-
-    builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
-    builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
-    builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
-
-    builder.setDefaultStringPiece("424");
-    builder.setDefaultCord("425");
-
-    builder.setOneofUint32(601);
-    builder.setOneofNestedMessage(
-        TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
-    builder.setOneofString("603");
-    builder.setOneofBytes(toBytes("604"));
-  }
-
   /**
    * Set every field of {@code message} to the values expected by
    * {@code assertAllFieldsSet()}.
@@ -1383,23 +1207,13 @@
     return registry.getUnmodifiable();
   }
 
-  public static ExtensionRegistryLite getExtensionRegistryLite() {
-    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
-    registerAllExtensionsLite(registry);
-    return registry.getUnmodifiable();
-  }
-
   /**
    * Register all of {@code TestAllExtensions}'s extensions with the
    * given {@link ExtensionRegistry}.
    */
   public static void registerAllExtensions(ExtensionRegistry registry) {
     UnittestProto.registerAllExtensions(registry);
-    registerAllExtensionsLite(registry);
-  }
-
-  public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
-    UnittestLite.registerAllExtensions(registry);
+    TestUtilLite.registerAllExtensionsLite(registry);
   }
 
   /**
@@ -2193,195 +2007,6 @@
   // Lite extensions
 
   /**
-   * Set every field of {@code message} to the values expected by
-   * {@code assertAllExtensionsSet()}.
-   */
-  public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
-    message.setExtension(optionalInt32ExtensionLite   , 101);
-    message.setExtension(optionalInt64ExtensionLite   , 102L);
-    message.setExtension(optionalUint32ExtensionLite  , 103);
-    message.setExtension(optionalUint64ExtensionLite  , 104L);
-    message.setExtension(optionalSint32ExtensionLite  , 105);
-    message.setExtension(optionalSint64ExtensionLite  , 106L);
-    message.setExtension(optionalFixed32ExtensionLite , 107);
-    message.setExtension(optionalFixed64ExtensionLite , 108L);
-    message.setExtension(optionalSfixed32ExtensionLite, 109);
-    message.setExtension(optionalSfixed64ExtensionLite, 110L);
-    message.setExtension(optionalFloatExtensionLite   , 111F);
-    message.setExtension(optionalDoubleExtensionLite  , 112D);
-    message.setExtension(optionalBoolExtensionLite    , true);
-    message.setExtension(optionalStringExtensionLite  , "115");
-    message.setExtension(optionalBytesExtensionLite   , toBytes("116"));
-
-    message.setExtension(optionalGroupExtensionLite,
-      OptionalGroup_extension_lite.newBuilder().setA(117).build());
-    message.setExtension(optionalNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
-    message.setExtension(optionalForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(119).build());
-    message.setExtension(optionalImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(120).build());
-    message.setExtension(optionalPublicImportMessageExtensionLite,
-      PublicImportMessageLite.newBuilder().setE(126).build());
-    message.setExtension(optionalLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
-
-    message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
-    message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-    message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
-    message.setExtension(optionalStringPieceExtensionLite, "124");
-    message.setExtension(optionalCordExtensionLite, "125");
-
-    // -----------------------------------------------------------------
-
-    message.addExtension(repeatedInt32ExtensionLite   , 201);
-    message.addExtension(repeatedInt64ExtensionLite   , 202L);
-    message.addExtension(repeatedUint32ExtensionLite  , 203);
-    message.addExtension(repeatedUint64ExtensionLite  , 204L);
-    message.addExtension(repeatedSint32ExtensionLite  , 205);
-    message.addExtension(repeatedSint64ExtensionLite  , 206L);
-    message.addExtension(repeatedFixed32ExtensionLite , 207);
-    message.addExtension(repeatedFixed64ExtensionLite , 208L);
-    message.addExtension(repeatedSfixed32ExtensionLite, 209);
-    message.addExtension(repeatedSfixed64ExtensionLite, 210L);
-    message.addExtension(repeatedFloatExtensionLite   , 211F);
-    message.addExtension(repeatedDoubleExtensionLite  , 212D);
-    message.addExtension(repeatedBoolExtensionLite    , true);
-    message.addExtension(repeatedStringExtensionLite  , "215");
-    message.addExtension(repeatedBytesExtensionLite   , toBytes("216"));
-
-    message.addExtension(repeatedGroupExtensionLite,
-      RepeatedGroup_extension_lite.newBuilder().setA(217).build());
-    message.addExtension(repeatedNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
-    message.addExtension(repeatedForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(219).build());
-    message.addExtension(repeatedImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(220).build());
-    message.addExtension(repeatedLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
-
-    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
-    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
-    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
-
-    message.addExtension(repeatedStringPieceExtensionLite, "224");
-    message.addExtension(repeatedCordExtensionLite, "225");
-
-    // Add a second one of each field.
-    message.addExtension(repeatedInt32ExtensionLite   , 301);
-    message.addExtension(repeatedInt64ExtensionLite   , 302L);
-    message.addExtension(repeatedUint32ExtensionLite  , 303);
-    message.addExtension(repeatedUint64ExtensionLite  , 304L);
-    message.addExtension(repeatedSint32ExtensionLite  , 305);
-    message.addExtension(repeatedSint64ExtensionLite  , 306L);
-    message.addExtension(repeatedFixed32ExtensionLite , 307);
-    message.addExtension(repeatedFixed64ExtensionLite , 308L);
-    message.addExtension(repeatedSfixed32ExtensionLite, 309);
-    message.addExtension(repeatedSfixed64ExtensionLite, 310L);
-    message.addExtension(repeatedFloatExtensionLite   , 311F);
-    message.addExtension(repeatedDoubleExtensionLite  , 312D);
-    message.addExtension(repeatedBoolExtensionLite    , false);
-    message.addExtension(repeatedStringExtensionLite  , "315");
-    message.addExtension(repeatedBytesExtensionLite   , toBytes("316"));
-
-    message.addExtension(repeatedGroupExtensionLite,
-      RepeatedGroup_extension_lite.newBuilder().setA(317).build());
-    message.addExtension(repeatedNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
-    message.addExtension(repeatedForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(319).build());
-    message.addExtension(repeatedImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(320).build());
-    message.addExtension(repeatedLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
-
-    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
-    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
-    message.addExtension(repeatedStringPieceExtensionLite, "324");
-    message.addExtension(repeatedCordExtensionLite, "325");
-
-    // -----------------------------------------------------------------
-
-    message.setExtension(defaultInt32ExtensionLite   , 401);
-    message.setExtension(defaultInt64ExtensionLite   , 402L);
-    message.setExtension(defaultUint32ExtensionLite  , 403);
-    message.setExtension(defaultUint64ExtensionLite  , 404L);
-    message.setExtension(defaultSint32ExtensionLite  , 405);
-    message.setExtension(defaultSint64ExtensionLite  , 406L);
-    message.setExtension(defaultFixed32ExtensionLite , 407);
-    message.setExtension(defaultFixed64ExtensionLite , 408L);
-    message.setExtension(defaultSfixed32ExtensionLite, 409);
-    message.setExtension(defaultSfixed64ExtensionLite, 410L);
-    message.setExtension(defaultFloatExtensionLite   , 411F);
-    message.setExtension(defaultDoubleExtensionLite  , 412D);
-    message.setExtension(defaultBoolExtensionLite    , false);
-    message.setExtension(defaultStringExtensionLite  , "415");
-    message.setExtension(defaultBytesExtensionLite   , toBytes("416"));
-
-    message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
-    message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
-    message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
-
-    message.setExtension(defaultStringPieceExtensionLite, "424");
-    message.setExtension(defaultCordExtensionLite, "425");
-
-    message.setExtension(oneofUint32ExtensionLite, 601);
-    message.setExtension(oneofNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
-    message.setExtension(oneofStringExtensionLite, "603");
-    message.setExtension(oneofBytesExtensionLite, toBytes("604"));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Modify the repeated extensions of {@code message} to contain the values
-   * expected by {@code assertRepeatedExtensionsModified()}.
-   */
-  public static void modifyRepeatedExtensions(
-      TestAllExtensionsLite.Builder message) {
-    message.setExtension(repeatedInt32ExtensionLite   , 1, 501);
-    message.setExtension(repeatedInt64ExtensionLite   , 1, 502L);
-    message.setExtension(repeatedUint32ExtensionLite  , 1, 503);
-    message.setExtension(repeatedUint64ExtensionLite  , 1, 504L);
-    message.setExtension(repeatedSint32ExtensionLite  , 1, 505);
-    message.setExtension(repeatedSint64ExtensionLite  , 1, 506L);
-    message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
-    message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
-    message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
-    message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
-    message.setExtension(repeatedFloatExtensionLite   , 1, 511F);
-    message.setExtension(repeatedDoubleExtensionLite  , 1, 512D);
-    message.setExtension(repeatedBoolExtensionLite    , 1, true);
-    message.setExtension(repeatedStringExtensionLite  , 1, "515");
-    message.setExtension(repeatedBytesExtensionLite   , 1, toBytes("516"));
-
-    message.setExtension(repeatedGroupExtensionLite, 1,
-      RepeatedGroup_extension_lite.newBuilder().setA(517).build());
-    message.setExtension(repeatedNestedMessageExtensionLite, 1,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
-    message.setExtension(repeatedForeignMessageExtensionLite, 1,
-      ForeignMessageLite.newBuilder().setC(519).build());
-    message.setExtension(repeatedImportMessageExtensionLite, 1,
-      ImportMessageLite.newBuilder().setD(520).build());
-    message.setExtension(repeatedLazyMessageExtensionLite, 1,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
-
-    message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
-    message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
-    message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
-
-    message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
-    message.setExtension(repeatedCordExtensionLite, 1, "525");
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
    * Assert (using {@code junit.framework.Assert}} that all extensions of
    * {@code message} are set to the values assigned by {@code setAllExtensions}.
    */
@@ -2880,38 +2505,6 @@
     assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
   }
 
-  public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
-    message.addExtension(packedInt32ExtensionLite   , 601);
-    message.addExtension(packedInt64ExtensionLite   , 602L);
-    message.addExtension(packedUint32ExtensionLite  , 603);
-    message.addExtension(packedUint64ExtensionLite  , 604L);
-    message.addExtension(packedSint32ExtensionLite  , 605);
-    message.addExtension(packedSint64ExtensionLite  , 606L);
-    message.addExtension(packedFixed32ExtensionLite , 607);
-    message.addExtension(packedFixed64ExtensionLite , 608L);
-    message.addExtension(packedSfixed32ExtensionLite, 609);
-    message.addExtension(packedSfixed64ExtensionLite, 610L);
-    message.addExtension(packedFloatExtensionLite   , 611F);
-    message.addExtension(packedDoubleExtensionLite  , 612D);
-    message.addExtension(packedBoolExtensionLite    , true);
-    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
-    // Add a second one of each field.
-    message.addExtension(packedInt32ExtensionLite   , 701);
-    message.addExtension(packedInt64ExtensionLite   , 702L);
-    message.addExtension(packedUint32ExtensionLite  , 703);
-    message.addExtension(packedUint64ExtensionLite  , 704L);
-    message.addExtension(packedSint32ExtensionLite  , 705);
-    message.addExtension(packedSint64ExtensionLite  , 706L);
-    message.addExtension(packedFixed32ExtensionLite , 707);
-    message.addExtension(packedFixed64ExtensionLite , 708L);
-    message.addExtension(packedSfixed32ExtensionLite, 709);
-    message.addExtension(packedSfixed64ExtensionLite, 710L);
-    message.addExtension(packedFloatExtensionLite   , 711F);
-    message.addExtension(packedDoubleExtensionLite  , 712D);
-    message.addExtension(packedBoolExtensionLite    , false);
-    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-  }
-
   public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
     Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite   ));
     Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite   ));
@@ -3015,6 +2608,9 @@
       case FOO_CORD:
         Assert.assertTrue(message.hasFooCord());
         break;
+      case FOO_STRING_PIECE:
+        Assert.assertTrue(message.hasFooStringPiece());
+        break;
       case FOO_BYTES:
         Assert.assertTrue(message.hasFooBytes());
         break;
@@ -3032,6 +2628,8 @@
         break;
       case FOO_NOT_SET:
         break;
+      default:
+        // TODO(b/18683919): go/enum-switch-lsc
     }
   }
 
@@ -4182,7 +3780,8 @@
 
   private static File getTestDataDir() {
     // Search each parent directory looking for "src/google/protobuf".
-    File ancestor = new File(".");
+    File ancestor = new File(System.getProperty("protobuf.dir", "."));
+    String initialPath = ancestor.getAbsolutePath();
     try {
       ancestor = ancestor.getCanonicalFile();
     } catch (IOException e) {
@@ -4199,7 +3798,7 @@
     throw new RuntimeException(
       "Could not find golden files.  This test must be run from within the " +
       "protobuf source package so that it can read test data files from the " +
-      "C++ source tree.");
+      "C++ source tree: " + initialPath);
   }
 
   /**
@@ -4263,7 +3862,7 @@
 
     private int invalidations;
 
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    @Override
     public void markDirty() {
       invalidations++;
     }
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtilLite.java b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
new file mode 100644
index 0000000..8f33fa1
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
@@ -0,0 +1,559 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+
+/**
+ * Contains methods for setting fields of {@code TestAllTypesLite}, {@code TestAllExtensionsLite},
+ * and {@code TestPackedExtensionsLite}. This is analogous to the functionality in TestUtil.java but
+ * does not depend on the presence of any non-lite protos.
+ *
+ * <p>This code is not to be used outside of {@code com.google.protobuf} and
+ * subpackages.
+ */
+public final class TestUtilLite {
+  private TestUtilLite() {}
+
+  /** Helper to convert a String to ByteString. */
+  static ByteString toBytes(String str) {
+    return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
+  }
+
+  /**
+   * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypesLite.Builder)}.
+   */
+  public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    setAllFields(builder);
+    return builder;
+  }
+
+  /**
+   * Get a {@code TestAllExtensionsLite} with all fields set as they would be by
+   * {@link #setAllExtensions(TestAllExtensionsLite.Builder)}.
+   */
+  public static TestAllExtensionsLite getAllLiteExtensionsSet() {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    setAllExtensions(builder);
+    return builder.build();
+  }
+
+  public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
+    TestPackedExtensionsLite.Builder builder = TestPackedExtensionsLite.newBuilder();
+    setPackedExtensions(builder);
+    return builder.build();
+  }
+  
+  /**
+   * Set every field of {@code builder} to the values expected by
+   * {@code assertAllFieldsSet()}.
+   */
+  public static void setAllFields(TestAllTypesLite.Builder builder) {
+    builder.setOptionalInt32   (101);
+    builder.setOptionalInt64   (102);
+    builder.setOptionalUint32  (103);
+    builder.setOptionalUint64  (104);
+    builder.setOptionalSint32  (105);
+    builder.setOptionalSint64  (106);
+    builder.setOptionalFixed32 (107);
+    builder.setOptionalFixed64 (108);
+    builder.setOptionalSfixed32(109);
+    builder.setOptionalSfixed64(110);
+    builder.setOptionalFloat   (111);
+    builder.setOptionalDouble  (112);
+    builder.setOptionalBool    (true);
+    builder.setOptionalString  ("115");
+    builder.setOptionalBytes   (toBytes("116"));
+
+    builder.setOptionalGroup(
+        TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
+    builder.setOptionalNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    builder.setOptionalForeignMessage(
+        ForeignMessageLite.newBuilder().setC(119).build());
+    builder.setOptionalImportMessage(
+        ImportMessageLite.newBuilder().setD(120).build());
+    builder.setOptionalPublicImportMessage(
+        PublicImportMessageLite.newBuilder().setE(126).build());
+    builder.setOptionalLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+    builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.setOptionalStringPiece("124");
+    builder.setOptionalCord("125");
+
+    // -----------------------------------------------------------------
+
+    builder.addRepeatedInt32   (201);
+    builder.addRepeatedInt64   (202);
+    builder.addRepeatedUint32  (203);
+    builder.addRepeatedUint64  (204);
+    builder.addRepeatedSint32  (205);
+    builder.addRepeatedSint64  (206);
+    builder.addRepeatedFixed32 (207);
+    builder.addRepeatedFixed64 (208);
+    builder.addRepeatedSfixed32(209);
+    builder.addRepeatedSfixed64(210);
+    builder.addRepeatedFloat   (211);
+    builder.addRepeatedDouble  (212);
+    builder.addRepeatedBool    (true);
+    builder.addRepeatedString  ("215");
+    builder.addRepeatedBytes   (toBytes("216"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(219).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(220).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
+
+    builder.addRepeatedStringPiece("224");
+    builder.addRepeatedCord("225");
+
+    // Add a second one of each field.
+    builder.addRepeatedInt32   (301);
+    builder.addRepeatedInt64   (302);
+    builder.addRepeatedUint32  (303);
+    builder.addRepeatedUint64  (304);
+    builder.addRepeatedSint32  (305);
+    builder.addRepeatedSint64  (306);
+    builder.addRepeatedFixed32 (307);
+    builder.addRepeatedFixed64 (308);
+    builder.addRepeatedSfixed32(309);
+    builder.addRepeatedSfixed64(310);
+    builder.addRepeatedFloat   (311);
+    builder.addRepeatedDouble  (312);
+    builder.addRepeatedBool    (false);
+    builder.addRepeatedString  ("315");
+    builder.addRepeatedBytes   (toBytes("316"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(319).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(320).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.addRepeatedStringPiece("324");
+    builder.addRepeatedCord("325");
+
+    // -----------------------------------------------------------------
+
+    builder.setDefaultInt32   (401);
+    builder.setDefaultInt64   (402);
+    builder.setDefaultUint32  (403);
+    builder.setDefaultUint64  (404);
+    builder.setDefaultSint32  (405);
+    builder.setDefaultSint64  (406);
+    builder.setDefaultFixed32 (407);
+    builder.setDefaultFixed64 (408);
+    builder.setDefaultSfixed32(409);
+    builder.setDefaultSfixed64(410);
+    builder.setDefaultFloat   (411);
+    builder.setDefaultDouble  (412);
+    builder.setDefaultBool    (false);
+    builder.setDefaultString  ("415");
+    builder.setDefaultBytes   (toBytes("416"));
+
+    builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
+    builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
+    builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
+
+    builder.setDefaultStringPiece("424");
+    builder.setDefaultCord("425");
+
+    builder.setOneofUint32(601);
+    builder.setOneofNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    builder.setOneofString("603");
+    builder.setOneofBytes(toBytes("604"));
+  }
+
+  /**
+   * Get an unmodifiable {@link ExtensionRegistryLite} containing all the
+   * extensions of {@code TestAllExtensionsLite}.
+   */
+  public static ExtensionRegistryLite getExtensionRegistryLite() {
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    registerAllExtensionsLite(registry);
+    return registry.getUnmodifiable();
+  }
+
+  /**
+   * Register all of {@code TestAllExtensionsLite}'s extensions with the
+   * given {@link ExtensionRegistryLite}.
+   */
+  public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
+    UnittestLite.registerAllExtensions(registry);
+  }
+
+  // ===================================================================
+  // Lite extensions
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllExtensionsSet()}.
+   */
+  public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
+    message.setExtension(optionalInt32ExtensionLite   , 101);
+    message.setExtension(optionalInt64ExtensionLite   , 102L);
+    message.setExtension(optionalUint32ExtensionLite  , 103);
+    message.setExtension(optionalUint64ExtensionLite  , 104L);
+    message.setExtension(optionalSint32ExtensionLite  , 105);
+    message.setExtension(optionalSint64ExtensionLite  , 106L);
+    message.setExtension(optionalFixed32ExtensionLite , 107);
+    message.setExtension(optionalFixed64ExtensionLite , 108L);
+    message.setExtension(optionalSfixed32ExtensionLite, 109);
+    message.setExtension(optionalSfixed64ExtensionLite, 110L);
+    message.setExtension(optionalFloatExtensionLite   , 111F);
+    message.setExtension(optionalDoubleExtensionLite  , 112D);
+    message.setExtension(optionalBoolExtensionLite    , true);
+    message.setExtension(optionalStringExtensionLite  , "115");
+    message.setExtension(optionalBytesExtensionLite   , toBytes("116"));
+
+    message.setExtension(optionalGroupExtensionLite,
+      OptionalGroup_extension_lite.newBuilder().setA(117).build());
+    message.setExtension(optionalNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    message.setExtension(optionalForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(119).build());
+    message.setExtension(optionalImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(120).build());
+    message.setExtension(optionalPublicImportMessageExtensionLite,
+      PublicImportMessageLite.newBuilder().setE(126).build());
+    message.setExtension(optionalLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.setExtension(optionalStringPieceExtensionLite, "124");
+    message.setExtension(optionalCordExtensionLite, "125");
+
+    // -----------------------------------------------------------------
+
+    message.addExtension(repeatedInt32ExtensionLite   , 201);
+    message.addExtension(repeatedInt64ExtensionLite   , 202L);
+    message.addExtension(repeatedUint32ExtensionLite  , 203);
+    message.addExtension(repeatedUint64ExtensionLite  , 204L);
+    message.addExtension(repeatedSint32ExtensionLite  , 205);
+    message.addExtension(repeatedSint64ExtensionLite  , 206L);
+    message.addExtension(repeatedFixed32ExtensionLite , 207);
+    message.addExtension(repeatedFixed64ExtensionLite , 208L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 209);
+    message.addExtension(repeatedSfixed64ExtensionLite, 210L);
+    message.addExtension(repeatedFloatExtensionLite   , 211F);
+    message.addExtension(repeatedDoubleExtensionLite  , 212D);
+    message.addExtension(repeatedBoolExtensionLite    , true);
+    message.addExtension(repeatedStringExtensionLite  , "215");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("216"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(217).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(219).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(220).build());
+    message.addExtension(repeatedLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "224");
+    message.addExtension(repeatedCordExtensionLite, "225");
+
+    // Add a second one of each field.
+    message.addExtension(repeatedInt32ExtensionLite   , 301);
+    message.addExtension(repeatedInt64ExtensionLite   , 302L);
+    message.addExtension(repeatedUint32ExtensionLite  , 303);
+    message.addExtension(repeatedUint64ExtensionLite  , 304L);
+    message.addExtension(repeatedSint32ExtensionLite  , 305);
+    message.addExtension(repeatedSint64ExtensionLite  , 306L);
+    message.addExtension(repeatedFixed32ExtensionLite , 307);
+    message.addExtension(repeatedFixed64ExtensionLite , 308L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 309);
+    message.addExtension(repeatedSfixed64ExtensionLite, 310L);
+    message.addExtension(repeatedFloatExtensionLite   , 311F);
+    message.addExtension(repeatedDoubleExtensionLite  , 312D);
+    message.addExtension(repeatedBoolExtensionLite    , false);
+    message.addExtension(repeatedStringExtensionLite  , "315");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("316"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(317).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(319).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(320).build());
+    message.addExtension(repeatedLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "324");
+    message.addExtension(repeatedCordExtensionLite, "325");
+
+    // -----------------------------------------------------------------
+
+    message.setExtension(defaultInt32ExtensionLite   , 401);
+    message.setExtension(defaultInt64ExtensionLite   , 402L);
+    message.setExtension(defaultUint32ExtensionLite  , 403);
+    message.setExtension(defaultUint64ExtensionLite  , 404L);
+    message.setExtension(defaultSint32ExtensionLite  , 405);
+    message.setExtension(defaultSint64ExtensionLite  , 406L);
+    message.setExtension(defaultFixed32ExtensionLite , 407);
+    message.setExtension(defaultFixed64ExtensionLite , 408L);
+    message.setExtension(defaultSfixed32ExtensionLite, 409);
+    message.setExtension(defaultSfixed64ExtensionLite, 410L);
+    message.setExtension(defaultFloatExtensionLite   , 411F);
+    message.setExtension(defaultDoubleExtensionLite  , 412D);
+    message.setExtension(defaultBoolExtensionLite    , false);
+    message.setExtension(defaultStringExtensionLite  , "415");
+    message.setExtension(defaultBytesExtensionLite   , toBytes("416"));
+
+    message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(defaultStringPieceExtensionLite, "424");
+    message.setExtension(defaultCordExtensionLite, "425");
+
+    message.setExtension(oneofUint32ExtensionLite, 601);
+    message.setExtension(oneofNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    message.setExtension(oneofStringExtensionLite, "603");
+    message.setExtension(oneofBytesExtensionLite, toBytes("604"));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated extensions of {@code message} to contain the values
+   * expected by {@code assertRepeatedExtensionsModified()}.
+   */
+  public static void modifyRepeatedExtensions(
+      TestAllExtensionsLite.Builder message) {
+    message.setExtension(repeatedInt32ExtensionLite   , 1, 501);
+    message.setExtension(repeatedInt64ExtensionLite   , 1, 502L);
+    message.setExtension(repeatedUint32ExtensionLite  , 1, 503);
+    message.setExtension(repeatedUint64ExtensionLite  , 1, 504L);
+    message.setExtension(repeatedSint32ExtensionLite  , 1, 505);
+    message.setExtension(repeatedSint64ExtensionLite  , 1, 506L);
+    message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
+    message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
+    message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
+    message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
+    message.setExtension(repeatedFloatExtensionLite   , 1, 511F);
+    message.setExtension(repeatedDoubleExtensionLite  , 1, 512D);
+    message.setExtension(repeatedBoolExtensionLite    , 1, true);
+    message.setExtension(repeatedStringExtensionLite  , 1, "515");
+    message.setExtension(repeatedBytesExtensionLite   , 1, toBytes("516"));
+
+    message.setExtension(repeatedGroupExtensionLite, 1,
+      RepeatedGroup_extension_lite.newBuilder().setA(517).build());
+    message.setExtension(repeatedNestedMessageExtensionLite, 1,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
+    message.setExtension(repeatedForeignMessageExtensionLite, 1,
+      ForeignMessageLite.newBuilder().setC(519).build());
+    message.setExtension(repeatedImportMessageExtensionLite, 1,
+      ImportMessageLite.newBuilder().setD(520).build());
+    message.setExtension(repeatedLazyMessageExtensionLite, 1,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
+    message.setExtension(repeatedCordExtensionLite, 1, "525");
+  }
+
+  public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
+    message.addExtension(packedInt32ExtensionLite   , 601);
+    message.addExtension(packedInt64ExtensionLite   , 602L);
+    message.addExtension(packedUint32ExtensionLite  , 603);
+    message.addExtension(packedUint64ExtensionLite  , 604L);
+    message.addExtension(packedSint32ExtensionLite  , 605);
+    message.addExtension(packedSint64ExtensionLite  , 606L);
+    message.addExtension(packedFixed32ExtensionLite , 607);
+    message.addExtension(packedFixed64ExtensionLite , 608L);
+    message.addExtension(packedSfixed32ExtensionLite, 609);
+    message.addExtension(packedSfixed64ExtensionLite, 610L);
+    message.addExtension(packedFloatExtensionLite   , 611F);
+    message.addExtension(packedDoubleExtensionLite  , 612D);
+    message.addExtension(packedBoolExtensionLite    , true);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    // Add a second one of each field.
+    message.addExtension(packedInt32ExtensionLite   , 701);
+    message.addExtension(packedInt64ExtensionLite   , 702L);
+    message.addExtension(packedUint32ExtensionLite  , 703);
+    message.addExtension(packedUint64ExtensionLite  , 704L);
+    message.addExtension(packedSint32ExtensionLite  , 705);
+    message.addExtension(packedSint64ExtensionLite  , 706L);
+    message.addExtension(packedFixed32ExtensionLite , 707);
+    message.addExtension(packedFixed64ExtensionLite , 708L);
+    message.addExtension(packedSfixed32ExtensionLite, 709);
+    message.addExtension(packedSfixed64ExtensionLite, 710L);
+    message.addExtension(packedFloatExtensionLite   , 711F);
+    message.addExtension(packedDoubleExtensionLite  , 712D);
+    message.addExtension(packedBoolExtensionLite    , false);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
new file mode 100644
index 0000000..e338af2
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
@@ -0,0 +1,182 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseInfoTree}.
+ */
+public class TextFormatParseInfoTreeTest extends TestCase {
+
+  private static final Descriptor DESCRIPTOR = TestAllTypes.getDescriptor();
+  private static final FieldDescriptor OPTIONAL_INT32 =
+      DESCRIPTOR.findFieldByName("optional_int32");
+  private static final FieldDescriptor OPTIONAL_BOOLEAN =
+      DESCRIPTOR.findFieldByName("optional_boolean");
+  private static final FieldDescriptor REPEATED_INT32 =
+      DESCRIPTOR.findFieldByName("repeated_int32");
+  private static final FieldDescriptor OPTIONAL_NESTED_MESSAGE =
+      DESCRIPTOR.findFieldByName("optional_nested_message");
+  private static final FieldDescriptor REPEATED_NESTED_MESSAGE =
+      DESCRIPTOR.findFieldByName("repeated_nested_message");
+  private static final FieldDescriptor FIELD_BB =
+      TestAllTypes.NestedMessage.getDescriptor().findFieldByName("bb");
+
+  private static final TextFormatParseLocation LOC0 = TextFormatParseLocation.create(1, 2);
+  private static final TextFormatParseLocation LOC1 = TextFormatParseLocation.create(2, 3);
+
+  private TextFormatParseInfoTree.Builder rootBuilder;
+
+  @Override
+  public void setUp() {
+    rootBuilder = TextFormatParseInfoTree.builder();
+  }
+
+  public void testBuildEmptyParseTree() {
+    TextFormatParseInfoTree tree = rootBuilder.build();
+    assertTrue(tree.getLocations(null).isEmpty());
+  }
+
+  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());
+    }
+
+  public void testGetLocationsReturnsNoParseLocationsForUnknownField() {
+    assertTrue(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));
+  }
+
+  public void testGetLocationThrowsIllegalArgumentExceptionForUnknownField() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    try {
+      root.getNestedTree(OPTIONAL_INT32, 0);
+      fail("Did not detect unknown field");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetLocationThrowsIllegalArgumentExceptionForInvalidIndex() {
+    TextFormatParseInfoTree root = rootBuilder.setLocation(OPTIONAL_INT32, LOC0).build();
+    try {
+      root.getLocation(OPTIONAL_INT32, 1);
+      fail("Invalid index not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+    try {
+      root.getLocation(OPTIONAL_INT32, -1);
+      fail("Negative index not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  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());
+  }
+
+  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");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetNestedTreesReturnsNoParseInfoTreesForUnknownField() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertTrue(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).isEmpty());
+  }
+
+  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");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+    try {
+      rootBuilder.build().getNestedTree(OPTIONAL_NESTED_MESSAGE, -1);
+      fail("Invalid submessage index (-1) not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetNestedTreesReturnsSingleTree() {
+    rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertEquals(1, root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).size());
+    TextFormatParseInfoTree subtree = root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).get(0);
+    assertNotNull(subtree);
+  }
+
+  public void testGetNestedTreesReturnsMultipleTrees() {
+    TextFormatParseInfoTree.Builder subtree1Builder =
+        rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
+    subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+    subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+    TextFormatParseInfoTree.Builder subtree2Builder =
+        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());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
new file mode 100644
index 0000000..c42bfa6
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
@@ -0,0 +1,86 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseLocation}.
+ */
+public class TextFormatParseLocationTest extends TestCase {
+
+  public void testCreateEmpty() {
+    TextFormatParseLocation location = TextFormatParseLocation.create(-1, -1);
+    assertEquals(TextFormatParseLocation.EMPTY, location);
+  }
+
+  public void testCreate() {
+    TextFormatParseLocation location = TextFormatParseLocation.create(2, 1);
+    assertEquals(2, location.getLine());
+    assertEquals(1, location.getColumn());
+  }
+
+  public void testCreateThrowsIllegalArgumentExceptionForInvalidIndex() {
+    try {
+      TextFormatParseLocation.create(-1, 0);
+      fail("Should throw IllegalArgumentException if line is less than 0");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+    try {
+      TextFormatParseLocation.create(0, -1);
+      fail("Should throw, column < 0");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+  }
+
+  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());
+  }
+
+  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);
+  }
+}
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 1df4fad..720061d 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -30,8 +30,13 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
+import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
+import map_test.MapTestProto.TestMap;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import protobuf_unittest.UnittestProto.OneString;
@@ -40,11 +45,11 @@
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestRequired;
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
-
-import junit.framework.TestCase;
-
 import java.io.StringReader;
+import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Test case for {@link TextFormat}.
@@ -56,12 +61,11 @@
 public class TextFormatTest extends TestCase {
 
   // A basic string with different escapable characters for testing.
-  private final static String kEscapeTestString =
-      "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
-          + "slashes \\";
+  private static final String ESCAPE_TEST_STRING =
+      "\"A string with ' characters \n and \r newlines and \t tabs and \001 " + "slashes \\";
 
   // A representation of the above string with all the characters escaped.
-  private final static String kEscapeTestStringEscaped =
+  private static final String ESCAPE_TEST_STRING_ESCAPED =
       "\\\"A string with \\' characters \\n and \\r newlines "
           + "and \\t tabs and \\001 slashes \\\\";
 
@@ -167,6 +171,7 @@
 
   // Creates an example unknown field set.
   private UnknownFieldSet makeUnknownFieldSet() {
+
     return UnknownFieldSet.newBuilder()
         .addField(5,
             UnknownFieldSet.Field.newBuilder()
@@ -174,6 +179,12 @@
             .addFixed32(2)
             .addFixed64(3)
             .addLengthDelimited(ByteString.copyFromUtf8("4"))
+            .addLengthDelimited(UnknownFieldSet.newBuilder()
+                .addField(12,
+                    UnknownFieldSet.Field.newBuilder()
+                        .addVarint(6)
+                        .build())
+                .build().toByteString())
             .addGroup(
                 UnknownFieldSet.newBuilder()
                 .addField(10,
@@ -206,20 +217,23 @@
         .build();
 
     assertEquals(
-      "5: 1\n" +
-      "5: 0x00000002\n" +
-      "5: 0x0000000000000003\n" +
-      "5: \"4\"\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.printToString(message));
+        "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.printToString(message));
   }
 
   public void testPrintField() throws Exception {
@@ -315,19 +329,58 @@
 
   // =================================================================
 
-  public void testParse() throws Exception {
+  public void testMerge() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(allFieldsSetText, builder);
     TestUtil.assertAllFieldsSet(builder.build());
   }
 
-  public void testParseReader() throws Exception {
+  public void testParse() throws Exception {
+    TestUtil.assertAllFieldsSet(
+        TextFormat.parse(allFieldsSetText, TestAllTypes.class));
+  }
+
+  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());
+  }
+
+  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());
+  }
+
+  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());
+  }
+
+  public void testParseUninitialized() throws Exception {
+    try {
+      TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(),
+                       TestRequired.class);
+      fail("Expected UninitializedMessageException.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: b, c", e.getMessage());
+    }
+  }
+
+  public void testMergeReader() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(new StringReader(allFieldsSetText), builder);
     TestUtil.assertAllFieldsSet(builder.build());
   }
 
-  public void testParseExtensions() throws Exception {
+  public void testMergeExtensions() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TextFormat.merge(allExtensionsSetText,
                      TestUtil.getExtensionRegistry(),
@@ -335,7 +388,14 @@
     TestUtil.assertAllExtensionsSet(builder.build());
   }
 
-  public void testParseCompatibility() throws Exception {
+  public void testParseExtensions() throws Exception {
+    TestUtil.assertAllExtensionsSet(
+        TextFormat.parse(allExtensionsSetText,
+                         TestUtil.getExtensionRegistry(),
+                         TestAllExtensions.class));
+  }
+
+  public void testMergeAndParseCompatibility() throws Exception {
     String original = "repeated_float: inf\n" +
                       "repeated_float: -inf\n" +
                       "repeated_float: nan\n" +
@@ -360,21 +420,29 @@
                         "repeated_double: Infinity\n" +
                         "repeated_double: -Infinity\n" +
                         "repeated_double: NaN\n";
+
+    // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(original, builder);
     assertEquals(canonical, builder.build().toString());
+
+    // Test parse().
+    assertEquals(canonical,
+                 TextFormat.parse(original, TestAllTypes.class).toString());
   }
 
-  public void testParseExotic() throws Exception {
+  public void testMergeAndParseExotic() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(exoticText, 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());
   }
 
-  public void testParseMessageSet() throws Exception {
+  public void testMergeMessageSet() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -400,7 +468,7 @@
       TestMessageSetExtension1.messageSetExtension).getI());
   }
 
-  public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+  public void testMergeMessageSetWithOverwriteForbidden() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -427,20 +495,20 @@
     }
   }
 
-  public void testParseNumericEnum() throws Exception {
+  public void testMergeNumericEnum() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_nested_enum: 2", builder);
     assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
   }
 
-  public void testParseAngleBrackets() throws Exception {
+  public void testMergeAngleBrackets() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
     assertTrue(builder.hasOptionalGroup());
     assertEquals(1, builder.getOptionalGroup().getA());
   }
 
-  public void testParseComment() throws Exception {
+  public void testMergeComment() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(
       "# this is a comment\n" +
@@ -452,6 +520,7 @@
   }
 
   private void assertParseError(String error, String text) {
+    // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
@@ -459,6 +528,15 @@
     } catch (TextFormat.ParseException e) {
       assertEquals(error, e.getMessage());
     }
+
+    // Test parse().
+    try {
+      TextFormat.parse(
+          text, TestUtil.getExtensionRegistry(), TestAllTypes.class);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
   }
 
 
@@ -497,10 +575,10 @@
         "integer: 82301481290849012385230157",
       "optional_int32: 82301481290849012385230157");
     assertParseError(
-      "1:16: Expected \"true\" or \"false\".",
+      "1:16: Expected \"true\" or \"false\". Found \"maybe\".",
       "optional_bool: maybe");
     assertParseError(
-      "1:16: Expected \"true\" or \"false\".",
+      "1:16: Expected \"true\" or \"false\". Found \"2\".",
       "optional_bool: 2");
     assertParseError(
       "1:18: Expected string.",
@@ -520,15 +598,16 @@
       "optional_string: \"ueoauaoe\n" +
       "optional_int32: 123");
     assertParseError(
-      "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
+      "1:2: Input contains unknown fields and/or extensions:\n" +
+      "1:2:\tprotobuf_unittest.TestAllTypes.[nosuchext]",
       "[nosuchext]: 123");
     assertParseError(
       "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
         "not extend message type \"protobuf_unittest.TestAllTypes\".",
       "[protobuf_unittest.optional_int32_extension]: 123");
     assertParseError(
-      "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
-        "named \"nosuchfield\".",
+      "1:1: Input contains unknown fields and/or extensions:\n" +
+      "1:1:\tprotobuf_unittest.TestAllTypes.nosuchfield",
       "nosuchfield: 123");
     assertParseError(
       "1:21: Expected \">\".",
@@ -563,10 +642,18 @@
       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(kEscapeTestStringEscaped,
-      TextFormat.escapeText(kEscapeTestString));
-    assertEquals(kEscapeTestString,
-      TextFormat.unescapeText(kEscapeTestStringEscaped));
+    assertEquals(ESCAPE_TEST_STRING_ESCAPED, TextFormat.escapeText(ESCAPE_TEST_STRING));
+    assertEquals(ESCAPE_TEST_STRING, TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED));
+
+    // Invariant
+    assertEquals("hello",
+        TextFormat.escapeBytes(bytes("hello")));
+    assertEquals("hello",
+        TextFormat.escapeText("hello"));
+    assertEquals(bytes("hello"),
+        TextFormat.unescapeBytes("hello"));
+    assertEquals("hello",
+        TextFormat.unescapeText("hello"));
 
     // Unicode handling.
     assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
@@ -763,11 +850,14 @@
   public void testParseBoolean() throws Exception {
     String goodText =
         "repeated_bool: t  repeated_bool : 0\n" +
-        "repeated_bool :f repeated_bool:1";
+        "repeated_bool :f repeated_bool:1\n" +
+        "repeated_bool: False repeated_bool: True";
     String goodTextCanonical =
         "repeated_bool: true\n" +
         "repeated_bool: false\n" +
         "repeated_bool: false\n" +
+        "repeated_bool: true\n" +
+        "repeated_bool: false\n" +
         "repeated_bool: true\n";
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(goodText, builder);
@@ -811,7 +901,6 @@
 
   private void assertPrintFieldValue(String expect, Object value,
       String fieldName) throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     StringBuilder sb = new StringBuilder();
     TextFormat.printFieldValue(
         TestAllTypes.getDescriptor().findFieldByName(fieldName),
@@ -847,7 +936,7 @@
   }
 
   public void testShortDebugString_unknown() {
-    assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+    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.shortDebugString(makeUnknownFieldSet()));
@@ -927,6 +1016,7 @@
   }
 
 
+  // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
   public void testParseNonRepeatedFields() throws Exception {
     assertParseSuccessWithOverwriteForbidden(
         "repeated_int32: 1\n" +
@@ -937,6 +1027,7 @@
     assertParseSuccessWithOverwriteForbidden(
         "repeated_nested_message { bb: 1 }\n" +
         "repeated_nested_message { bb: 2 }\n");
+
     assertParseErrorWithOverwriteForbidden(
         "3:17: Non-repeated field " +
         "\"protobuf_unittest.TestAllTypes.optional_int32\" " +
@@ -975,12 +1066,40 @@
     assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
     assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
     assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
+    // See also testMapShortForm.
+  }
+
+  public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
+    assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: []");
+    assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
+    assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n");
+    assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n");
+    // See also testMapShortFormEmpty.
+  }
+
+  public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
+    assertParseErrorWithOverwriteForbidden(
+        "1:38: Expected identifier. Found \']\'",
+        "repeated_foreign_enum: [FOREIGN_FOO, ]\n");
+    assertParseErrorWithOverwriteForbidden(
+        "1:22: Couldn't parse integer: For input string: \"]\"",
+        "repeated_int32: [ 1, ]\n");
+    assertParseErrorWithOverwriteForbidden(
+        "1:25: Expected \"{\".",
+        "RepeatedGroup [{ a: 1 },]\n");
+    assertParseErrorWithOverwriteForbidden(
+        "1:37: Expected \"{\".",
+        "repeated_nested_message [{ bb: 1 }, ]\n");
+    // See also testMapShortFormTrailingComma.
   }
 
   public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
     assertParseErrorWithOverwriteForbidden(
         "1:17: Couldn't parse integer: For input string: \"[\"",
         "optional_int32: [1]\n");
+    assertParseErrorWithOverwriteForbidden(
+        "1:17: Couldn't parse integer: For input string: \"[\"",
+        "optional_int32: []\n");
   }
 
   // =======================================================================
@@ -1018,4 +1137,182 @@
     assertFalse(oneof.hasFooString());
     assertTrue(oneof.hasFooInt());
   }
+
+  // =======================================================================
+  // test map
+
+  public void testMapTextFormat() throws Exception {
+    TestMap message =
+        TestMap.newBuilder()
+            .putInt32ToStringField(10, "apple")
+            .putInt32ToStringField(20, "banana")
+            .putInt32ToStringField(30, "cherry")
+            .build();
+    String text = TextFormat.printToUnicodeString(message);
+    {
+      TestMap.Builder dest = TestMap.newBuilder();
+      TextFormat.merge(text, dest);
+      assertEquals(message, dest.build());
+    }
+    {
+      TestMap.Builder dest = TestMap.newBuilder();
+      parserWithOverwriteForbidden.merge(text, dest);
+      assertEquals(message, dest.build());
+    }
+  }
+
+  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);
+    TestMap message = dest.build();
+    assertEquals(2, message.getStringToInt32Field().size());
+    assertEquals(2, message.getInt32ToMessageField().size());
+    assertEquals(10, message.getStringToInt32Field().get("x").intValue());
+    assertEquals(200, message.getInt32ToMessageField().get(2).getValue());
+  }
+
+  public void testMapShortFormEmpty() throws Exception {
+    String text = "string_to_int32_field []\n"
+        + "int32_to_message_field: []\n";
+    TestMap.Builder dest = TestMap.newBuilder();
+    parserWithOverwriteForbidden.merge(text, dest);
+    TestMap message = dest.build();
+    assertEquals(0, message.getStringToInt32Field().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+  }
+
+  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.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals("1:48: Expected \"{\".", e.getMessage());
+    }
+  }
+
+  public void testMapOverwrite() throws Exception {
+    String text =
+        "int32_to_int32_field { key: 1 value: 10 }\n"
+            + "int32_to_int32_field { key: 2 value: 20 }\n"
+            + "int32_to_int32_field { key: 1 value: 30 }\n";
+
+    {
+      // With default parser, last value set for the key holds.
+      TestMap.Builder builder = TestMap.newBuilder();
+      defaultParser.merge(text, builder);
+      TestMap map = builder.build();
+      assertEquals(2, map.getInt32ToInt32Field().size());
+      assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+    }
+
+    {
+      // With overwrite forbidden, same behavior.
+      // TODO(b/29122459): Expect parse exception here.
+      TestMap.Builder builder = TestMap.newBuilder();
+      defaultParser.merge(text, builder);
+      TestMap map = builder.build();
+      assertEquals(2, map.getInt32ToInt32Field().size());
+      assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
+    }
+  }
+
+  // =======================================================================
+  // test location information
+
+  public void testParseInfoTreeBuilding() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder();
+    // Set to allow unknown fields
+    TextFormat.Parser parser =
+        TextFormat.Parser.newBuilder()
+            .setParseInfoTreeBuilder(treeBuilder)
+            .build();
+
+    final String stringData =
+        "optional_int32: 1\n"
+        + "optional_int64: 2\n"
+        + "  optional_double: 2.4\n"
+        + "repeated_int32: 5\n"
+        + "repeated_int32: 10\n"
+        + "optional_nested_message <\n"
+        + "  bb: 78\n"
+        + ">\n"
+        + "repeated_nested_message <\n"
+        + "  bb: 79\n"
+        + ">\n"
+        + "repeated_nested_message <\n"
+        + "  bb: 80\n"
+        + ">";
+
+    parser.merge(stringData, builder);
+    TextFormatParseInfoTree tree = treeBuilder.build();
+
+    // Verify that the tree has the correct positions.
+    assertLocation(tree, descriptor, "optional_int32", 0, 0, 0);
+    assertLocation(tree, descriptor, "optional_int64", 0, 1, 0);
+    assertLocation(tree, descriptor, "optional_double", 0, 2, 2);
+
+    assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0);
+    assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0);
+
+    assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0);
+    assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0);
+    assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0);
+
+    // Check for fields not set. For an invalid field, the location returned should be -1, -1.
+    assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1);
+    assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1);
+
+    // Verify inside the nested message.
+    FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message");
+
+    TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2);
+
+    // Verify inside another nested message.
+    nestedField = descriptor.findFieldByName("repeated_nested_message");
+    nestedTree = tree.getNestedTrees(nestedField).get(0);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2);
+
+    nestedTree = tree.getNestedTrees(nestedField).get(1);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2);
+
+    // Verify a NULL tree for an unknown nested field.
+    try {
+      tree.getNestedTree(nestedField, 2);
+      fail("unknown nested field should throw");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+  }
+
+  private void assertLocation(
+      TextFormatParseInfoTree tree,
+      final Descriptor descriptor,
+      final String fieldName,
+      int index,
+      int line,
+      int column) {
+    List<TextFormatParseLocation> locs = tree.getLocations(descriptor.findFieldByName(fieldName));
+    if (index < locs.size()) {
+      TextFormatParseLocation location = locs.get(index);
+      TextFormatParseLocation expected = TextFormatParseLocation.create(line, column);
+      assertEquals(expected, location);
+    } else if (line != -1 && column != -1) {
+      fail(
+          String.format(
+              "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected",
+              index,
+              line,
+              column));
+    }
+  }
 }
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 8f45976..88cbbf8 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
@@ -36,7 +36,6 @@
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
 import com.google.protobuf.TextFormat.ParseException;
-
 import junit.framework.TestCase;
 
 /**
@@ -151,18 +150,15 @@
     assertEquals(4321, unknown4321.getNumber());
     assertEquals(5432, unknown5432.getNumber());
     assertEquals(6543, unknown6543.getNumber());
-    
+
     // Unknown EnumValueDescriptor will map to UNRECOGNIZED.
     assertEquals(
-        TestAllTypes.NestedEnum.valueOf(unknown4321),
-        TestAllTypes.NestedEnum.UNRECOGNIZED);
+        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown4321));
     assertEquals(
-        TestAllTypes.NestedEnum.valueOf(unknown5432),
-        TestAllTypes.NestedEnum.UNRECOGNIZED);
+        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown5432));
     assertEquals(
-        TestAllTypes.NestedEnum.valueOf(unknown6543),
-        TestAllTypes.NestedEnum.UNRECOGNIZED);
-    
+        TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown6543));
+
     // Setters also accept unknown EnumValueDescriptor.
     builder.setField(optionalNestedEnumField, unknown6543);
     builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321);
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
index dc98737..8ce0ca7 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -30,16 +30,25 @@
 
 package com.google.protobuf;
 
+import static junit.framework.TestCase.assertEquals;
+
 import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
-
-import junit.framework.TestCase;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link UnknownFieldSetLite}.
@@ -47,47 +56,44 @@
  * @author dweis@google.com (Daniel Weis)
  */
 public class UnknownFieldSetLiteTest extends TestCase {
-
-  public void testNoDataIsDefaultInstance() {
-    assertSame(
-        UnknownFieldSetLite.getDefaultInstance(),
-        UnknownFieldSetLite.newBuilder()
-            .build());
-  }
-  
-  public void testBuilderReuse() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-    builder.build();
-
-    try {
-      builder.build();
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeVarintField(5, 1);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // Expected.
-    }
+  @Override
+  public void setUp() throws Exception {
+    allFields = TestUtil.getAllSet();
+    allFieldsData = allFields.toByteString();
+    emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+    unknownFields = emptyMessage.getUnknownFields();
   }
 
-  public void testBuilderReuse_empty() {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.build();
-    builder.build();
+  TestAllTypes allFields;
+  ByteString allFieldsData;
+
+  // Constructs a protocol buffer which contains fields with all the same
+  // numbers as allFieldsData except that each field is some other wire
+  // type.
+  private ByteString getBizarroData() throws Exception {
+    UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+    UnknownFieldSet.Field varintField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+    UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+    for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
+      if (entry.getValue().getVarintList().isEmpty()) {
+        // Original field is not a varint, so use a varint.
+        bizarroFields.addField(entry.getKey(), varintField);
+      } else {
+        // Original field *is* a varint, so use something else.
+        bizarroFields.addField(entry.getKey(), fixed32Field);
+      }
+    }
+
+    return bizarroFields.build().toByteString();
   }
-  
+
+  // An empty message that has been parsed from allFieldsData.  So, it has
+  // unknown fields of every type.
+  TestEmptyMessage emptyMessage;
+  UnknownFieldSet unknownFields;
+
   public void testDefaultInstance() {
     UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
 
@@ -95,6 +101,14 @@
     assertEquals(ByteString.EMPTY, toByteString(unknownFields));
   }
 
+  public void testEmptyInstance() {
+    UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+
+    assertEquals(0, instance.getSerializedSize());
+    assertEquals(ByteString.EMPTY, toByteString(instance));
+    assertEquals(UnknownFieldSetLite.getDefaultInstance(), instance);
+  }
+
   public void testMergeFieldFrom() throws IOException {
     Foo foo = Foo.newBuilder()
       .setValue(2)
@@ -121,6 +135,25 @@
     assertEquals(foo.toByteString().size(), instance.getSerializedSize());
   }
 
+  public void testHashCodeAfterDeserialization() throws IOException {
+    Foo foo = Foo.newBuilder()
+      .setValue(2)
+      .build();
+
+    Foo fooDeserialized = Foo.parseFrom(foo.toByteArray());
+
+    assertEquals(fooDeserialized, foo);
+    assertEquals(foo.hashCode(), fooDeserialized.hashCode());
+  }
+
+  public void testNewInstanceHashCode() {
+    UnknownFieldSetLite emptyFieldSet = UnknownFieldSetLite.getDefaultInstance();
+    UnknownFieldSetLite paddedFieldSet = UnknownFieldSetLite.newInstance();
+
+    assertEquals(emptyFieldSet, paddedFieldSet);
+    assertEquals(emptyFieldSet.hashCode(), paddedFieldSet.hashCode());
+  }
+
   public void testMergeVarintField() throws IOException {
     UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
     unknownFields.mergeVarintField(10, 2);
@@ -365,4 +398,203 @@
     }
     return ByteString.copyFrom(byteArrayOutputStream.toByteArray());
   }
+
+  public void testSerializeLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes message = TestAllTypes.parseFrom(data);
+    TestUtil.assertAllFieldsSet(message);
+    assertEquals(allFieldsData, data);
+  }
+
+  public void testAllExtensionsLite() throws Exception {
+    TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
+    ByteString allExtensionsData = allExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllExtensions message = TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertAllExtensionsSet(message);
+    assertEquals(allExtensionsData, data);
+  }
+
+  public void testAllPackedFieldsLite() throws Exception {
+    TestPackedTypes allPackedFields = TestUtil.getPackedSet();
+    ByteString allPackedData = allPackedFields.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedTypes message = TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedFieldsSet(message);
+    assertEquals(allPackedData, data);
+  }
+
+  public void testAllPackedExtensionsLite() throws Exception {
+    TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
+    ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedExtensions message =
+        TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedExtensionsSet(message);
+    assertEquals(allPackedExtensionsData, data);
+  }
+
+  public void testCopyFromLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite).build();
+    assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
+  }
+
+  public void testMergeFromLite() throws Exception {
+    TestAllTypes message1 =
+        TestAllTypes.newBuilder()
+            .setOptionalInt32(1)
+            .setOptionalString("foo")
+            .addRepeatedString("bar")
+            .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
+            .build();
+
+    TestAllTypes message2 =
+        TestAllTypes.newBuilder()
+            .setOptionalInt64(2)
+            .setOptionalString("baz")
+            .addRepeatedString("qux")
+            .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
+            .build();
+
+    ByteString data1 = message1.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data1);
+    ByteString data2 = message2.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data2);
+
+    message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
+    emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
+            .mergeFrom(emptyMessageLite2)
+            .build();
+
+    data1 = emptyMessageLite1.toByteString();
+    message2 = TestAllTypes.parseFrom(data1);
+
+    assertEquals(message1, message2);
+  }
+
+  public void testWrongTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
+
+    assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
+  }
+
+  public void testUnknownExtensionsLite() throws Exception {
+    // Make sure fields are properly parsed to the UnknownFieldSet even when
+    // they are declared as extension numbers.
+
+    UnittestLite.TestEmptyMessageWithExtensionsLite message =
+        UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
+
+    assertEquals(allFieldsData, message.toByteString());
+  }
+
+  public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing extensions.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the byte strings
+    // should be the same.
+    assertEquals(emptyMessageLite.toByteString(), allExtensionsMessage.toByteString());
+  }
+
+  public void testParseUnknownEnumValueLite() throws Exception {
+    Descriptors.FieldDescriptor singularField =
+        TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+    Descriptors.FieldDescriptor repeatedField =
+        TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+    assertNotNull(singularField);
+    assertNotNull(repeatedField);
+
+    ByteString data =
+        UnknownFieldSet.newBuilder()
+            .addField(
+                singularField.getNumber(),
+                UnknownFieldSet.Field.newBuilder()
+                    .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+                    .addVarint(5) // not valid
+                    .build())
+            .addField(
+                repeatedField.getNumber(),
+                UnknownFieldSet.Field.newBuilder()
+                    .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+                    .addVarint(4) // not valid
+                    .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+                    .addVarint(6) // not valid
+                    .build())
+            .build()
+            .toByteString();
+
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data);
+    data = emptyMessageLite.toByteString();
+
+    {
+      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());
+    }
+
+    {
+      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());
+    }
+  }
+
+  public void testClearLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite1).clear().build();
+    assertEquals(0, emptyMessageLite2.getSerializedSize());
+    ByteString data = emptyMessageLite2.toByteString();
+    assertEquals(0, data.size());
+  }
 }
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 8c9dcaf..1a84806 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -38,11 +38,9 @@
 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
-
-import junit.framework.TestCase;
-
 import java.util.Arrays;
 import java.util.Map;
+import junit.framework.TestCase;
 
 /**
  * Tests related to unknown field handling.
@@ -50,6 +48,7 @@
  * @author kenton@google.com (Kenton Varda)
  */
 public class UnknownFieldSetTest extends TestCase {
+  @Override
   public void setUp() throws Exception {
     descriptor = TestAllTypes.getDescriptor();
     allFields = TestUtil.getAllSet();
@@ -446,208 +445,4 @@
   }
 
   // =================================================================
-
-  public void testSerializeLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllTypes message = TestAllTypes.parseFrom(data);
-    TestUtil.assertAllFieldsSet(message);
-    assertEquals(allFieldsData, data);
-  }
-
-  public void testAllExtensionsLite() throws Exception {
-    TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
-    ByteString allExtensionsData = allExtensions.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllExtensions message =
-        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertAllExtensionsSet(message);
-    assertEquals(allExtensionsData, data);
-  }
-
-  public void testAllPackedFieldsLite() throws Exception {
-    TestPackedTypes allPackedFields = TestUtil.getPackedSet();
-    ByteString allPackedData = allPackedFields.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestPackedTypes message =
-        TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertPackedFieldsSet(message);
-    assertEquals(allPackedData, data);
-  }
-
-  public void testAllPackedExtensionsLite() throws Exception {
-    TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
-    ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestPackedExtensions message =
-        TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertPackedExtensionsSet(message);
-    assertEquals(allPackedExtensionsData, data);
-  }
-
-  public void testCopyFromLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.newBuilder()
-        .mergeFrom(emptyMessageLite).build();
-    assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
-  }
-
-  public void testMergeFromLite() throws Exception {
-    TestAllTypes message1 = TestAllTypes.newBuilder()
-        .setOptionalInt32(1)
-        .setOptionalString("foo")
-        .addRepeatedString("bar")
-        .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
-        .build();
-
-    TestAllTypes message2 = TestAllTypes.newBuilder()
-        .setOptionalInt64(2)
-        .setOptionalString("baz")
-        .addRepeatedString("qux")
-        .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
-        .build();
-
-    ByteString data1 = message1.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data1);
-    ByteString data2 = message2.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data2);
-
-    message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
-    emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
-                        .mergeFrom(emptyMessageLite2).build();
-
-    data1 = emptyMessageLite1.toByteString();
-    message2 = TestAllTypes.parseFrom(data1);
-
-    assertEquals(message1, message2);
-  }
-
-  public void testWrongTypeTreatedAsUnknownLite() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
-
-    assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
-  }
-
-  public void testUnknownExtensionsLite() throws Exception {
-    // Make sure fields are properly parsed to the UnknownFieldSet even when
-    // they are declared as extension numbers.
-
-    UnittestLite.TestEmptyMessageWithExtensionsLite message =
-      UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
-
-    assertEquals(allFieldsData, message.toByteString());
-  }
-
-  public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing extensions.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllExtensions allExtensionsMessage =
-      TestAllExtensions.parseFrom(bizarroData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
-
-    // All fields should have been interpreted as unknown, so the byte strings
-    // should be the same.
-    assertEquals(emptyMessageLite.toByteString(),
-                 allExtensionsMessage.toByteString());
-  }
-
-  public void testParseUnknownEnumValueLite() throws Exception {
-    Descriptors.FieldDescriptor singularField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
-    Descriptors.FieldDescriptor repeatedField =
-      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
-    assertNotNull(singularField);
-    assertNotNull(repeatedField);
-
-    ByteString data =
-      UnknownFieldSet.newBuilder()
-        .addField(singularField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
-            .addVarint(5)   // not valid
-            .build())
-        .addField(repeatedField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
-            .addVarint(4)   // not valid
-            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
-            .addVarint(6)   // not valid
-            .build())
-        .build()
-        .toByteString();
-
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data);
-    data = emptyMessageLite.toByteString();
-
-    {
-      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());
-    }
-
-    {
-      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());
-    }
-  }
-
-  public void testClearLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.newBuilder()
-        .mergeFrom(emptyMessageLite1).clear().build();
-    assertEquals(0, emptyMessageLite2.getSerializedSize());
-    ByteString data = emptyMessageLite2.toByteString();
-    assertEquals(0, data.size());
-  }
-
 }
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 b1c75fc..00f201c 100644
--- a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
@@ -30,11 +30,10 @@
 
 package com.google.protobuf;
 
-import junit.framework.TestCase;
-
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
+import junit.framework.TestCase;
 
 /**
  * Tests for {@link UnmodifiableLazyStringList}.
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 0175005..03c33ec 100644
--- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -30,26 +30,23 @@
 
 package com.google.protobuf;
 
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.List;
-
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestExtensionInsideTable;
 import protobuf_unittest.UnittestProto.TestFieldOrderings;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestMset.RawMessageSet;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+import junit.framework.TestCase;
 
 /**
  * Tests related to parsing and serialization.
@@ -127,32 +124,6 @@
     TestUtil.assertPackedFieldsSet(message2);
   }
 
-  public void testSerializeExtensionsLite() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
-    // it should work.
-
-    TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
-    TestUtil.assertAllFieldsSet(message2);
-  }
-
-  public void testSerializePackedExtensionsLite() throws Exception {
-    // TestPackedTypes and TestPackedExtensions should have compatible wire
-    // formats; check that they serialize to the same string.
-    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    TestPackedTypes message2 = TestUtil.getPackedSet();
-    ByteString rawBytes2 = message2.toByteString();
-
-    assertEquals(rawBytes, rawBytes2);
-  }
-
   public void testParseExtensions() throws Exception {
     // TestAllTypes and TestAllExtensions should have compatible wire formats,
     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
@@ -182,48 +153,6 @@
     TestUtil.assertPackedExtensionsSet(message2);
   }
 
-  public void testParseExtensionsLite() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
-    // it should work.
-
-    TestAllTypes message = TestUtil.getAllSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
-
-    TestAllExtensionsLite message2 =
-      TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
-
-    TestUtil.assertAllExtensionsSet(message2);
-
-    // Try again using a full extension registry.
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
-
-    TestAllExtensionsLite message3 =
-      TestAllExtensionsLite.parseFrom(rawBytes, registry);
-
-    TestUtil.assertAllExtensionsSet(message3);
-  }
-
-  public void testParsePackedExtensionsLite() throws Exception {
-    // Ensure that packed extensions can be properly parsed.
-    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
-
-    TestPackedExtensionsLite message2 =
-        TestPackedExtensionsLite.parseFrom(rawBytes, registry);
-
-    TestUtil.assertPackedExtensionsSet(message2);
-  }
-
-  public void testExtensionsSerializedSize() throws Exception {
-    assertNotSame(TestUtil.getAllSet().getSerializedSize(),
-                  TestUtil.getAllExtensionsSet().getSerializedSize());
-  }
-
   public void testSerializeDelimited() throws Exception {
     ByteArrayOutputStream output = new ByteArrayOutputStream();
     TestUtil.getAllSet().writeDelimitedTo(output);
@@ -307,6 +236,26 @@
                                    getTestFieldOrderingsRegistry());
     assertEquals(source, dest);
   }
+  
+  private static ExtensionRegistry getTestExtensionInsideTableRegistry() {
+    ExtensionRegistry result = ExtensionRegistry.newInstance();
+    result.add(UnittestProto.testExtensionInsideTableExtension);
+    return result;
+  }
+  
+  public void testExtensionInsideTable() throws Exception {
+    // Make sure the extension within the range of table is parsed correctly in experimental
+    // runtime.
+    TestExtensionInsideTable source =
+        TestExtensionInsideTable.newBuilder()
+        .setField1(1)
+        .setExtension(UnittestProto.testExtensionInsideTableExtension, 23)
+        .build();
+    TestExtensionInsideTable dest =
+        TestExtensionInsideTable.parseFrom(source.toByteString(),
+            getTestExtensionInsideTableRegistry());
+    assertEquals(source, dest);
+  }
 
   public void testParseMultipleExtensionRangesDynamic() throws Exception {
     // Same as above except with DynamicMessage.
diff --git a/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto b/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto
new file mode 100644
index 0000000..ca90e92
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/deprecated_file.proto
@@ -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.
+
+syntax = "proto3";
+
+package deprecated_file;
+
+option deprecated = true;
+
+// TODO (liujisi): Add deprecation options on messages, enums fields as well and
+// add tests to verify those annotations are actually generated.
diff --git a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
index 8f3ca8c..2367bd8 100644
--- a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
@@ -36,7 +36,6 @@
 
 option java_package = "com.google.protobuf";
 option java_outer_classname = "FieldPresenceTestProto";
-option java_generate_equals_and_hash = true;
 
 message TestAllTypes {
   enum NestedEnum {
@@ -54,6 +53,7 @@
   NestedEnum optional_nested_enum = 4;
   NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
+  NestedMessage optional_lazy_message = 7 [lazy=true];
 
   oneof oneof_field {
     int32 oneof_int32 = 11;
@@ -81,6 +81,7 @@
   TestAllTypes.NestedEnum optional_nested_enum = 4;
   TestAllTypes.NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
+  TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy=true];
 }
 
 message TestRepeatedFieldsOnly {
diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
index 8683725..b18b0d7 100644
--- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
+++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
@@ -34,14 +34,26 @@
 
 package protobuf_unittest.lite_equals_and_hash;
 
-// This proto definition is used to test that java_generate_equals_and_hash
-// works correctly with the LITE_RUNTIME.
-option java_generate_equals_and_hash = true;
 option optimize_for = LITE_RUNTIME;
 
+message TestOneofEquals {
+  oneof oneof_field {
+    string name = 1;
+    int32 value = 2;
+  }
+}
+
 message Foo {
   optional int32 value = 1;
   repeated Bar bar = 2;
+  map<string, string> my_map = 3;
+  oneof Single {
+    sint64 sint64 = 4;
+    // LINT: ALLOW_GROUPS
+    group MyGroup = 5 {
+      optional int32 value = 1;
+    }
+  }
 
   extensions 100 to max;
 }
@@ -70,3 +82,8 @@
   }
 }
 
+message TestRecursiveOneof {
+  oneof Foo {
+    TestRecursiveOneof r = 1;
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
index d5418f2..2ca0251 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -32,7 +32,6 @@
 
 
 option java_outer_classname = "MapForProto2TestProto";
-option java_generate_equals_and_hash = true;
 
 message TestMap {
   message MessageValue {
@@ -70,6 +69,53 @@
   optional int32 value = 1;
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
+
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
+
+// Used to test that java reserved words can be used as protobuf field names
+// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
+// subset of them chosen to cover various keyword categories like
+// type, modifier, declaration, etc.
+message ReservedAsMapField {
+  map<string, uint32> if = 1;
+  map<string, uint32> const = 2;
+  map<string, uint32> private = 3;
+  map<string, uint32> class = 4;
+  map<string, uint32> int = 5;
+  map<string, uint32> void = 6;
+  map<string, uint32> string = 7; // These are also proto keywords
+  map<string, uint32> package = 8;
+  map<string, uint32> enum = 9; // Most recent Java reserved word
+  map<string, uint32> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
+
+message ReservedAsMapFieldWithEnumValue {
+  enum SampleEnum {
+    A = 0;
+    B = 1;
+  }
+  map<string, SampleEnum> if = 1;
+  map<string, SampleEnum> const = 2;
+  map<string, SampleEnum> private = 3;
+  map<string, SampleEnum> class = 4;
+  map<string, SampleEnum> int = 5;
+  map<string, SampleEnum> void = 6;
+  map<string, SampleEnum> string = 7; // These are also proto keywords
+  map<string, SampleEnum> package = 8;
+  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
+  map<string, SampleEnum> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
 package map_for_proto2_lite_test;
 option java_package = "map_lite_test";
 option optimize_for = LITE_RUNTIME;
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
index a9be516..974f8a2 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
@@ -34,7 +34,6 @@
 
 option java_package = "map_test";
 option java_outer_classname = "MapForProto2TestProto";
-option java_generate_equals_and_hash = true;
 
 message TestMap {
   message MessageValue {
@@ -72,3 +71,50 @@
   optional int32 value = 1;
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
+
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
+
+// Used to test that java reserved words can be used as protobuf field names
+// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
+// subset of them chosen to cover various keyword categories like
+// type, modifier, declaration, etc.
+message ReservedAsMapField {
+  map<string, uint32> if = 1;
+  map<string, uint32> const = 2;
+  map<string, uint32> private = 3;
+  map<string, uint32> class = 4;
+  map<string, uint32> int = 5;
+  map<string, uint32> void = 6;
+  map<string, uint32> string = 7; // These are also proto keywords
+  map<string, uint32> package = 8;
+  map<string, uint32> enum = 9; // Most recent Java reserved word
+  map<string, uint32> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
+
+message ReservedAsMapFieldWithEnumValue {
+  enum SampleEnum {
+    A = 0;
+    B = 1;
+  }
+  map<string, SampleEnum> if = 1;
+  map<string, SampleEnum> const = 2;
+  map<string, SampleEnum> private = 3;
+  map<string, SampleEnum> class = 4;
+  map<string, SampleEnum> int = 5;
+  map<string, SampleEnum> void = 6;
+  map<string, SampleEnum> string = 7; // These are also proto keywords
+  map<string, SampleEnum> package = 8;
+  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
+  map<string, SampleEnum> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
new file mode 100644
index 0000000..c04f5d5
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
@@ -0,0 +1,111 @@
+// 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.
+
+syntax = "proto3";
+
+package map_lite_test;
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "map_lite_test";
+option java_outer_classname = "MapTestProto";
+
+message TestMap {
+  message MessageValue {
+    int32 value = 1;
+  }
+  enum EnumValue {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+
+  map<int32, int32>        int32_to_int32_field = 1;
+  map<int32, string>       int32_to_string_field = 2;
+  map<int32, bytes>        int32_to_bytes_field = 3;
+  map<int32, EnumValue>    int32_to_enum_field = 4;
+  map<int32, MessageValue> int32_to_message_field = 5;
+  map<string, int32>       string_to_int32_field = 6;
+  map<uint32, int32>       uint32_to_int32_field = 7;
+  map<int64, int32>        int64_to_int32_field = 8;
+}
+
+// Used to test that a nested builder containing map fields will properly
+// propagate the onChange event and mark its parent dirty when a change
+// is made to a map field.
+message TestOnChangeEventPropagation {
+  TestMap optional_message = 1;
+}
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
+
+// Used to test that java reserved words can be used as protobuf field names
+// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
+// subset of them chosen to cover various keyword categories like
+// type, modifier, declaration, etc.
+message ReservedAsMapField {
+  map<string, uint32> if = 1;
+  map<string, uint32> const = 2;
+  map<string, uint32> private = 3;
+  map<string, uint32> class = 4;
+  map<string, uint32> int = 5;
+  map<string, uint32> void = 6;
+  map<string, uint32> string = 7; // These are also proto keywords
+  map<string, uint32> package = 8;
+  map<string, uint32> enum = 9; // Most recent Java reserved word
+  map<string, uint32> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
+
+message ReservedAsMapFieldWithEnumValue {
+  enum SampleEnum {
+    A = 0;
+    B = 1;
+  }
+  map<string, SampleEnum> if = 1;
+  map<string, SampleEnum> const = 2;
+  map<string, SampleEnum> private = 3;
+  map<string, SampleEnum> class = 4;
+  map<string, SampleEnum> int = 5;
+  map<string, SampleEnum> void = 6;
+  map<string, SampleEnum> string = 7; // These are also proto keywords
+  map<string, SampleEnum> package = 8;
+  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
+  map<string, SampleEnum> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
index 2280ac0..bc2105e 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -34,7 +34,6 @@
 
 option java_package = "map_test";
 option java_outer_classname = "MapTestProto";
-option java_generate_equals_and_hash = true;
 
 message TestMap {
   message MessageValue {
@@ -53,11 +52,59 @@
   map<int32, EnumValue>    int32_to_enum_field = 4;
   map<int32, MessageValue> int32_to_message_field = 5;
   map<string, int32>       string_to_int32_field = 6;
+  map<uint32, int32>       uint32_to_int32_field = 7;
+  map<int64, int32>        int64_to_int32_field = 8;
 }
 
-// Used to test that a nested bulider containing map fields will properly
+// Used to test that a nested builder containing map fields will properly
 // propagate the onChange event and mark its parent dirty when a change
 // is made to a map field.
 message TestOnChangeEventPropagation {
   TestMap optional_message = 1;
 }
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
+
+// Used to test that java reserved words can be used as protobuf field names
+// Not all reserved words are tested (to avoid bloat) but instead an arbitrary
+// subset of them chosen to cover various keyword categories like
+// type, modifier, declaration, etc.
+message ReservedAsMapField {
+  map<string, uint32> if = 1;
+  map<string, uint32> const = 2;
+  map<string, uint32> private = 3;
+  map<string, uint32> class = 4;
+  map<string, uint32> int = 5;
+  map<string, uint32> void = 6;
+  map<string, uint32> string = 7; // These are also proto keywords
+  map<string, uint32> package = 8;
+  map<string, uint32> enum = 9; // Most recent Java reserved word
+  map<string, uint32> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
+
+message ReservedAsMapFieldWithEnumValue {
+  enum SampleEnum {
+    A = 0;
+    B = 1;
+  }
+  map<string, SampleEnum> if = 1;
+  map<string, SampleEnum> const = 2;
+  map<string, SampleEnum> private = 3;
+  map<string, SampleEnum> class = 4;
+  map<string, SampleEnum> int = 5;
+  map<string, SampleEnum> void = 6;
+  map<string, SampleEnum> string = 7; // These are also proto keywords
+  map<string, SampleEnum> package = 8;
+  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
+  map<string, SampleEnum> null = 10;
+  // null is not a 'reserved word' per se but as a literal needs similar care
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
index 2b1f65e..ff5bf3a 100644
--- a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
+++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -43,7 +43,6 @@
 
 option java_package = "com.google.protobuf";
 option java_outer_classname = "TestBadIdentifiersProto";
-option java_generate_equals_and_hash = true;
 
 message TestMessage {
   optional string cached_size = 1;
@@ -149,6 +148,12 @@
   // the method getInt32FieldList().
   required int32 int32_field_list = 31;  // NO_PROTO3
 
+  // These field pairs have the same Java converted name
+  optional string field_name = 32; // NO_PROTO3
+  optional string field__name = 33; // NO_PROTO3
+  optional int32 _2conflict = 34; // NO_PROTO3
+  optional int32 __2conflict = 35;
+
   extensions 1000 to max;  // NO_PROTO3
 
   repeated int64 int64_field = 41;
@@ -167,3 +172,14 @@
 
   map<int32, int32> map_field = 1;
 }
+
+message TestLeadingNumberFields {
+  optional int32 _30day_impressions = 1;
+  repeated string _60day_impressions = 2;
+
+  optional string __2_underscores = 3;
+  repeated string __2repeated_underscores = 4;
+
+  optional int32 _32 = 32;
+  repeated int64 _64 = 64;
+}
diff --git a/java/lite.md b/java/lite.md
new file mode 100644
index 0000000..84a45ec
--- /dev/null
+++ b/java/lite.md
@@ -0,0 +1,50 @@
+# Protocol Buffers - Google's data interchange format
+
+Copyright 2008 Google Inc.
+
+https://developers.google.com/protocol-buffers/
+
+## Use Protobuf Java Lite Runtime
+
+Protobuf Java Lite runtime is separated from the main Java runtime because
+it's designed/implemented with different constraints. In particular, Java
+Lite runtime has a much smaller code size which makes it more suitable to
+be used on Android.
+
+To use Java Lite runtime, you need to install protoc and the protoc plugin for
+Java Lite runtime. You can obtain protoc following the instructions in the
+toplevel [README.md](../README.md) file. For the protoc plugin, you can
+download it from maven:
+
+    https://repo1.maven.org/maven2/com/google/protobuf/protoc-gen-javalite/
+
+Choose the version that works on your platform (e.g., on windows you can
+download `protoc-gen-javalite-3.0.0-windows-x86_32.exe`), rename it to
+protoc-gen-javalite (or protoc-gen-javalite.exe on windows) and place it
+in a directory where it can be find in PATH.
+
+Once you have the protoc and protoc plugin, you can generate Java Lite code
+for your .proto files:
+
+    $ protoc --javalite_out=${OUTPUT_DIR} path/to/your/proto/file
+
+Include the generated Java files in your project and add a dependency on the
+protobuf Java runtime. If you are using Maven, use the following:
+
+```xml
+<dependency>
+  <groupId>com.google.protobuf</groupId>
+  <artifactId>protobuf-lite</artifactId>
+  <version>3.0.1</version>
+</dependency>
+```
+
+Make sure the version number of the runtime matches (or is newer than) the
+version number of the protoc plugin. The version number of the protoc doesn't
+matter and any version >= 3.0.0 should work.
+
+### Use Protobuf Java Lite Runtime with Bazel
+
+Bazel has native build rules to work with protobuf. For Java Lite runtime,
+you can use the `java_lite_proto_library` rule. Check out [our build files
+examples](../examples/BUILD) to learn how to use it.
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
deleted file mode 100644
index 70c7d04..0000000
--- a/java/lite/pom.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>com.google.protobuf</groupId>
-    <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-2</version>
-  </parent>
-
-  <artifactId>protobuf-lite</artifactId>
-  <packaging>bundle</packaging>
-
-  <name>Protocol Buffers [Lite]</name>
-  <description>A trimmed-down version of the Protocol Buffers library.</description>
-
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymockclassextension</artifactId>
-    </dependency>
-  </dependencies>
-
-  <properties>
-    <core.root>../core</core.root>
-    <test.proto.dir>${core.root}/src/test/proto</test.proto.dir>
-  </properties>
-
-  <build>
-    <sourceDirectory>${core.root}/src/main/java</sourceDirectory>
-    <testSourceDirectory>${core.root}/src/test/java</testSourceDirectory>
-
-    <plugins>
-      <!-- Use Antrun plugin to generate sources with protoc -->
-      <plugin>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <!-- Generate core protos -->
-          <execution>
-            <id>generate-sources</id>
-            <phase>generate-sources</phase>
-            <configuration>
-              <target>
-                <ant antfile="${core.root}/generate-sources-build.xml"/>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-
-          <!-- Generate the test protos -->
-          <execution>
-            <id>generate-test-sources</id>
-            <phase>generate-test-sources</phase>
-            <configuration>
-              <target>
-                <ant antfile="${core.root}/generate-test-sources-build.xml"/>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-
-      <!-- Only compile a subset of the files -->
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
-          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
-          <includes>
-            <include>**/AbstractMessageLite.java</include>
-            <include>**/AbstractParser.java</include>
-            <include>**/AbstractProtobufList.java</include>
-            <include>**/BooleanArrayList.java</include>
-            <include>**/ByteString.java</include>
-            <include>**/CodedInputStream.java</include>
-            <include>**/CodedOutputStream.java</include>
-            <include>**/DoubleArrayList.java</include>
-            <include>**/ExtensionLite.java</include>
-            <include>**/ExtensionRegistryLite.java</include>
-            <include>**/FieldSet.java</include>
-            <include>**/FloatArrayList.java</include>
-            <include>**/GeneratedMessageLite.java</include>
-            <include>**/IntArrayList.java</include>
-            <include>**/Internal.java</include>
-            <include>**/InvalidProtocolBufferException.java</include>
-            <include>**/LazyFieldLite.java</include>
-            <include>**/LazyStringArrayList.java</include>
-            <include>**/LazyStringList.java</include>
-            <include>**/LongArrayList.java</include>
-            <include>**/MapEntryLite.java</include>
-            <include>**/MapFieldLite.java</include>
-            <include>**/MessageLite.java</include>
-            <include>**/MessageLiteOrBuilder.java</include>
-            <include>**/MessageLiteToString.java</include>
-            <include>**/MutabilityOracle.java</include>
-            <include>**/NioByteString.java</include>
-            <include>**/Parser.java</include>
-            <include>**/ProtobufArrayList.java</include>
-            <include>**/ProtocolStringList.java</include>
-            <include>**/RopeByteString.java</include>
-            <include>**/SmallSortedMap.java</include>
-            <include>**/TextFormatEscaper.java</include>
-            <include>**/UninitializedMessageException.java</include>
-            <include>**/UnknownFieldSetLite.java</include>
-            <include>**/UnmodifiableLazyStringList.java</include>
-            <include>**/UnsafeByteOperations.java</include>
-            <include>**/Utf8.java</include>
-            <include>**/WireFormat.java</include>
-          </includes>
-          <testIncludes>
-            <testInclude>**/*Lite.java</testInclude>
-            <testInclude>**/BooleanArrayListTest.java</testInclude>
-            <testInclude>**/DoubleArrayListTest.java</testInclude>
-            <testInclude>**/FloatArrayListTest.java</testInclude>
-            <testInclude>**/IntArrayListTest.java</testInclude>
-            <testInclude>**/LazyMessageLiteTest.java</testInclude>
-            <testInclude>**/LiteTest.java</testInclude>
-            <testInclude>**/LongArrayListTest.java</testInclude>
-            <testInclude>**/NioByteStringTest.java</testInclude>
-            <testInclude>**/ProtobufArrayListTest.java</testInclude>
-            <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
-          </testIncludes>
-        </configuration>
-      </plugin>
-
-      <!-- OSGI bundle configuration -->
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
-            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
-            <Export-Package>com.google.${project.artifactId};version=${project.version}</Export-Package>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-
-</project>
diff --git a/java/pom.xml b/java/pom.xml
index d5719ed..6526b65 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -11,7 +11,7 @@
 
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-parent</artifactId>
-  <version>3.0.0-beta-2</version>
+  <version>3.6.1</version>
   <packaging>pom</packaging>
 
   <name>Protocol Buffers [Parent]</name>
@@ -37,8 +37,8 @@
 
   <licenses>
     <license>
-      <name>New BSD license</name>
-      <url>http://www.opensource.org/licenses/bsd-license.php</url>
+      <name>3-Clause BSD License</name>
+      <url>https://opensource.org/licenses/BSD-3-Clause</url>
       <distribution>repo</distribution>
     </license>
   </licenses>
@@ -64,7 +64,7 @@
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
-        <version>4.4</version>
+        <version>4.12</version>
         <scope>test</scope>
       </dependency>
       <dependency>
@@ -82,7 +82,7 @@
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
-        <version>18.0</version>
+        <version>19.0</version>
       </dependency>
     </dependencies>
   </dependencyManagement>
@@ -92,10 +92,10 @@
       <plugins>
         <plugin>
           <artifactId>maven-compiler-plugin</artifactId>
-          <version>3.3</version>
+          <version>3.6.1</version>
           <configuration>
-            <source>1.6</source>
-            <target>1.6</target>
+            <source>1.7</source>
+            <target>1.7</target>
           </configuration>
         </plugin>
         <plugin>
@@ -150,6 +150,32 @@
       <build>
         <plugins>
           <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.2.1</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar-no-fork</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.9.1</version>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
             <artifactId>maven-gpg-plugin</artifactId>
             <version>1.6</version>
             <executions>
@@ -180,7 +206,6 @@
 
   <modules>
     <module>core</module>
-    <module>lite</module>
     <module>util</module>
   </modules>
 
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 26c12c8..f175cf1 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-2</version>
+    <version>3.6.1</version>
   </parent>
 
   <artifactId>protobuf-java-util</artifactId>
@@ -28,7 +28,7 @@
     <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
-      <version>2.3</version>
+      <version>2.7</version>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
@@ -79,12 +79,24 @@
         </executions>
       </plugin>
 
+      <!-- Add the generated test sources to the build -->
       <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <!-- Add the generated test sources to the build -->
-          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
-        </configuration>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-generated-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <goals>
+              <goal>add-test-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${generated.testsources.dir}</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
       </plugin>
 
       <!-- Configure the OSGI bundle -->
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
new file mode 100644
index 0000000..fb7f434
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -0,0 +1,311 @@
+// 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.util;
+
+import static com.google.common.math.IntMath.checkedAdd;
+import static com.google.common.math.IntMath.checkedSubtract;
+import static com.google.common.math.LongMath.checkedAdd;
+import static com.google.common.math.LongMath.checkedMultiply;
+import static com.google.common.math.LongMath.checkedSubtract;
+import static com.google.protobuf.util.Timestamps.MICROS_PER_SECOND;
+import static com.google.protobuf.util.Timestamps.MILLIS_PER_SECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_MILLISECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
+
+import com.google.protobuf.Duration;
+import java.text.ParseException;
+import java.util.Comparator;
+
+/**
+ * Utilities to help create/manipulate {@code protobuf/duration.proto}. All operations throw an
+ * {@link IllegalArgumentException} if the input(s) are not {@linkplain #isValid(Duration) valid}.
+ */
+public final class Durations {
+  static final long DURATION_SECONDS_MIN = -315576000000L;
+  static final long DURATION_SECONDS_MAX = 315576000000L;
+
+  /** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */
+  public static final Duration MIN_VALUE =
+      Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
+
+  /** A constant holding the maximum valid {@link Duration}, approximately {@code +10,000} years. */
+  public static final Duration MAX_VALUE =
+      Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build();
+
+  private Durations() {}
+
+  private static final Comparator<Duration> COMPARATOR =
+      new Comparator<Duration>() {
+        @Override
+        public int compare(Duration d1, Duration d2) {
+          checkValid(d1);
+          checkValid(d2);
+          int secDiff = Long.compare(d1.getSeconds(), d2.getSeconds());
+          return (secDiff != 0) ? secDiff : Integer.compare(d1.getNanos(), d2.getNanos());
+        }
+      };
+
+  /**
+   * Returns a {@link Comparator} for {@link Duration}s which sorts in increasing chronological
+   * order. Nulls and invalid {@link Duration}s are not allowed (see {@link #isValid}).
+   */
+  public static Comparator<Duration> comparator() {
+    return COMPARATOR;
+  }
+
+  /**
+   * Compares two durations. The value returned is identical to what would be returned by:
+   * {@code Durations.comparator().compare(x, y)}.
+   *
+   * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
+   *     and a value greater than {@code 0} if {@code x > y}
+   */
+  public static int compare(Duration x, Duration y) {
+    return COMPARATOR.compare(x, y);
+  }
+
+  /**
+   * Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the
+   * range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range
+   * [-999,999,999, +999,999,999].
+   *
+   * <p><b>Note:</b> Durations less than one second are represented with a 0 {@code seconds} field
+   * and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
+   * value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+   */
+  public static boolean isValid(Duration duration) {
+    return isValid(duration.getSeconds(), duration.getNanos());
+  }
+
+  /**
+   * Returns true if the given number of seconds and nanos is a valid {@link Duration}. The {@code
+   * seconds} value must be in the range [-315,576,000,000, +315,576,000,000]. The {@code nanos}
+   * value must be in the range [-999,999,999, +999,999,999].
+   *
+   * <p><b>Note:</b> Durations less than one second are represented with a 0 {@code seconds} field
+   * and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
+   * value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+   */
+  public static boolean isValid(long seconds, int nanos) {
+    if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
+      return false;
+    }
+    if (nanos < -999999999L || nanos >= NANOS_PER_SECOND) {
+      return false;
+    }
+    if (seconds < 0 || nanos < 0) {
+      if (seconds > 0 || nanos > 0) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
+  public static Duration checkValid(Duration duration) {
+    long seconds = duration.getSeconds();
+    int nanos = duration.getNanos();
+    if (!isValid(seconds, nanos)) {
+        throw new IllegalArgumentException(String.format(
+            "Duration is not valid. See proto definition for valid values. "
+            + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
+            + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+            + "Nanos must have the same sign as seconds", seconds, nanos));
+    }
+    return duration;
+  }
+
+  /**
+   * Convert Duration to string format. The string format will contains 3, 6, or 9 fractional digits
+   * depending on the precision required to represent the exact Duration value. For example: "1s",
+   * "1.010s", "1.000000100s", "-3.100s" The range that can be represented by Duration is from
+   * -315,576,000,000 to +315,576,000,000 inclusive (in seconds).
+   *
+   * @return The string representation of the given duration.
+   * @throws IllegalArgumentException if the given duration is not in the valid range.
+   */
+  public static String toString(Duration duration) {
+    checkValid(duration);
+
+    long seconds = duration.getSeconds();
+    int nanos = duration.getNanos();
+
+    StringBuilder result = new StringBuilder();
+    if (seconds < 0 || nanos < 0) {
+      result.append("-");
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    result.append(seconds);
+    if (nanos != 0) {
+      result.append(".");
+      result.append(Timestamps.formatNanos(nanos));
+    }
+    result.append("s");
+    return result.toString();
+  }
+
+  /**
+   * Parse from a string to produce a duration.
+   *
+   * @return A Duration parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+  public static Duration parse(String value) throws ParseException {
+    // Must ended with "s".
+    if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    boolean negative = false;
+    if (value.charAt(0) == '-') {
+      negative = true;
+      value = value.substring(1);
+    }
+    String secondValue = value.substring(0, value.length() - 1);
+    String nanoValue = "";
+    int pointPosition = secondValue.indexOf('.');
+    if (pointPosition != -1) {
+      nanoValue = secondValue.substring(pointPosition + 1);
+      secondValue = secondValue.substring(0, pointPosition);
+    }
+    long seconds = Long.parseLong(secondValue);
+    int nanos = nanoValue.isEmpty() ? 0 : Timestamps.parseNanos(nanoValue);
+    if (seconds < 0) {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    if (negative) {
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    try {
+      return normalizedDuration(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException("Duration value is out of range.", 0);
+    }
+  }
+
+  /** Create a Duration from the number of seconds. */
+  public static Duration fromSeconds(long seconds) {
+    return normalizedDuration(seconds, 0);
+  }
+
+  /**
+   * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
+   * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toSeconds(Duration duration) {
+    return checkValid(duration).getSeconds();
+  }
+
+  /** Create a Duration from the number of milliseconds. */
+  public static Duration fromMillis(long milliseconds) {
+    return normalizedDuration(
+        milliseconds / MILLIS_PER_SECOND,
+        (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the
+   * nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMillis(Duration duration) {
+    checkValid(duration);
+    return checkedAdd(
+        checkedMultiply(duration.getSeconds(), MILLIS_PER_SECOND),
+        duration.getNanos() / NANOS_PER_MILLISECOND);
+  }
+
+  /** Create a Duration from the number of microseconds. */
+  public static Duration fromMicros(long microseconds) {
+    return normalizedDuration(
+        microseconds / MICROS_PER_SECOND,
+        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the
+   * nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMicros(Duration duration) {
+    checkValid(duration);
+    return checkedAdd(
+        checkedMultiply(duration.getSeconds(), MICROS_PER_SECOND),
+        duration.getNanos() / NANOS_PER_MICROSECOND);
+  }
+
+  /** Create a Duration from the number of nanoseconds. */
+  public static Duration fromNanos(long nanoseconds) {
+    return normalizedDuration(
+        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /** Convert a Duration to the number of nanoseconds. */
+  public static long toNanos(Duration duration) {
+    checkValid(duration);
+    return checkedAdd(
+        checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
+  }
+
+  /** Add two durations. */
+  public static Duration add(Duration d1, Duration d2) {
+    checkValid(d1);
+    checkValid(d2);
+    return normalizedDuration(
+        checkedAdd(d1.getSeconds(), d2.getSeconds()), checkedAdd(d1.getNanos(), d2.getNanos()));
+  }
+
+  /** Subtract a duration from another. */
+  public static Duration subtract(Duration d1, Duration d2) {
+    checkValid(d1);
+    checkValid(d2);
+    return normalizedDuration(
+        checkedSubtract(d1.getSeconds(), d2.getSeconds()),
+        checkedSubtract(d1.getNanos(), d2.getNanos()));
+  }
+
+  static Duration normalizedDuration(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
+      nanos %= NANOS_PER_SECOND;
+    }
+    if (seconds > 0 && nanos < 0) {
+      nanos += NANOS_PER_SECOND; // no overflow since nanos is negative (and we're adding)
+      seconds--; // no overflow since seconds is positive (and we're decrementing)
+    }
+    if (seconds < 0 && nanos > 0) {
+      nanos -= NANOS_PER_SECOND; // no overflow since nanos is positive (and we're subtracting)
+      seconds++; // no overflow since seconds is negative (and we're incrementing)
+    }
+    Duration duration = Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+    return checkValid(duration);
+  }
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
index dc2f4b8..4a13fb1 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -34,10 +34,10 @@
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldMask;
 import com.google.protobuf.Message;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.logging.Logger;
 
@@ -59,26 +59,29 @@
  * intersection to two FieldMasks and traverse all fields specified by the
  * FieldMask in a message tree.
  */
-class FieldMaskTree {
-  private static final Logger logger =
-      Logger.getLogger(FieldMaskTree.class.getName());
-  
-  private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; 
+final class FieldMaskTree {
+  private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
 
-  private static class Node {
-    public TreeMap<String, Node> children = new TreeMap<String, Node>();
+  private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
+
+  private static final class Node {
+    final SortedMap<String, Node> children = new TreeMap<String, Node>();
   }
 
   private final Node root = new Node();
 
-  /** Creates an empty FieldMaskTree. */
-  public FieldMaskTree() {}
-  
-  /** Creates a FieldMaskTree for a given FieldMask. */
-  public FieldMaskTree(FieldMask mask) {
+  /**
+   * Creates an empty FieldMaskTree.
+   */
+  FieldMaskTree() {}
+
+  /**
+   * Creates a FieldMaskTree for a given FieldMask.
+   */
+  FieldMaskTree(FieldMask mask) {
     mergeFromFieldMask(mask);
   }
-  
+
   @Override
   public String toString() {
     return FieldMaskUtil.toString(toFieldMask());
@@ -94,7 +97,7 @@
    * Likewise, if the field path to add is a sub-path of an existing leaf node,
    * nothing will be changed in the tree.
    */
-  public FieldMaskTree addFieldPath(String path) {
+  FieldMaskTree addFieldPath(String path) {
     String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
     if (parts.length == 0) {
       return this;
@@ -121,19 +124,21 @@
     node.children.clear();
     return this;
   }
-  
+
   /**
    * Merges all field paths in a FieldMask into this tree.
    */
-  public FieldMaskTree mergeFromFieldMask(FieldMask mask) {
+  FieldMaskTree mergeFromFieldMask(FieldMask mask) {
     for (String path : mask.getPathsList()) {
       addFieldPath(path);
     }
     return this;
   }
 
-  /** Converts this tree to a FieldMask. */
-  public FieldMask toFieldMask() {
+  /**
+   * Converts this tree to a FieldMask.
+   */
+  FieldMask toFieldMask() {
     if (root.children.isEmpty()) {
       return FieldMask.getDefaultInstance();
     }
@@ -142,24 +147,24 @@
     return FieldMask.newBuilder().addAllPaths(paths).build();
   }
 
-  /** Gathers all field paths in a sub-tree. */
+  /**
+   * Gathers all field paths in a sub-tree.
+   */
   private void getFieldPaths(Node node, String path, List<String> paths) {
     if (node.children.isEmpty()) {
       paths.add(path);
       return;
     }
     for (Entry<String, Node> entry : node.children.entrySet()) {
-      String childPath = path.isEmpty()
-          ? entry.getKey() : path + "." + entry.getKey();
+      String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
       getFieldPaths(entry.getValue(), childPath, paths);
     }
   }
 
   /**
-   * Adds the intersection of this tree with the given {@code path} to
-   * {@code output}.
+   * Adds the intersection of this tree with the given {@code path} to {@code output}.
    */
-  public void intersectFieldPath(String path, FieldMaskTree output) {
+  void intersectFieldPath(String path, FieldMaskTree output) {
     if (root.children.isEmpty()) {
       return;
     }
@@ -190,14 +195,11 @@
   }
 
   /**
-   * Merges all fields specified by this FieldMaskTree from {@code source} to
-   * {@code destination}.
+   * Merges all fields specified by this FieldMaskTree from {@code source} to {@code destination}.
    */
-  public void merge(Message source, Message.Builder destination,
-      FieldMaskUtil.MergeOptions options) {
+  void merge(Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
     if (source.getDescriptorForType() != destination.getDescriptorForType()) {
-      throw new IllegalArgumentException(
-          "Cannot merge messages of different types.");
+      throw new IllegalArgumentException("Cannot merge messages of different types.");
     }
     if (root.children.isEmpty()) {
       return;
@@ -205,33 +207,54 @@
     merge(root, "", source, destination, options);
   }
 
-  /** Merges all fields specified by a sub-tree from {@code source} to
-   * {@code destination}.
+  /**
+   * Merges all fields specified by a sub-tree from {@code source} to {@code destination}.
    */
-  private void merge(Node node, String path, Message source,
-      Message.Builder destination, FieldMaskUtil.MergeOptions options) {
-    assert source.getDescriptorForType() == destination.getDescriptorForType();
-    
+  private void merge(
+      Node node,
+      String path,
+      Message source,
+      Message.Builder destination,
+      FieldMaskUtil.MergeOptions options) {
+    if (source.getDescriptorForType() != destination.getDescriptorForType()) {
+      throw new IllegalArgumentException(
+          String.format(
+              "source (%s) and destination (%s) descriptor must be equal",
+              source.getDescriptorForType(), destination.getDescriptorForType()));
+    }
+
     Descriptor descriptor = source.getDescriptorForType();
     for (Entry<String, Node> entry : node.children.entrySet()) {
-      FieldDescriptor field =
-          descriptor.findFieldByName(entry.getKey());
+      FieldDescriptor field = descriptor.findFieldByName(entry.getKey());
       if (field == null) {
-        logger.warning("Cannot find field \"" + entry.getKey()
-            + "\" in message type " + descriptor.getFullName());
+        logger.warning(
+            "Cannot find field \""
+                + entry.getKey()
+                + "\" in message type "
+                + descriptor.getFullName());
         continue;
       }
       if (!entry.getValue().children.isEmpty()) {
-        if (field.isRepeated()
-            || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
-          logger.warning("Field \"" + field.getFullName() + "\" is not a "
-              + "singluar message field and cannot have sub-fields.");
+        if (field.isRepeated() || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+          logger.warning(
+              "Field \""
+                  + field.getFullName()
+                  + "\" is not a "
+                  + "singluar message field and cannot have sub-fields.");
           continue;
         }
-        String childPath = path.isEmpty()
-            ? entry.getKey() : path + "." + entry.getKey();
-        merge(entry.getValue(), childPath, (Message) source.getField(field),
-            destination.getFieldBuilder(field), options);
+        if (!source.hasField(field) && !destination.hasField(field)) {
+          // If the message field is not present in both source and destination, skip recursing
+          // so we don't create unnecessary empty messages.
+          continue;
+        }
+        String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
+        merge(
+            entry.getValue(),
+            childPath,
+            (Message) source.getField(field),
+            destination.getFieldBuilder(field),
+            options);
         continue;
       }
       if (field.isRepeated()) {
@@ -245,13 +268,22 @@
       } else {
         if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
           if (options.replaceMessageFields()) {
-            destination.setField(field, source.getField(field));
+            if (!source.hasField(field)) {
+              destination.clearField(field);
+            } else {
+              destination.setField(field, source.getField(field));
+            }
           } else {
-            destination.getFieldBuilder(field).mergeFrom(
-                (Message) source.getField(field));
+            if (source.hasField(field)) {
+              destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field));
+            }
           }
         } else {
-          destination.setField(field, source.getField(field));
+          if (source.hasField(field) || !options.replacePrimitiveFields()) {
+            destination.setField(field, source.getField(field));
+          } else {
+            destination.clearField(field);
+          }
         }
       }
     }
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 0b3060a..b2f849c 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
@@ -32,6 +32,9 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.primitives.Ints;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
@@ -39,7 +42,9 @@
 import com.google.protobuf.Internal;
 import com.google.protobuf.Message;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
@@ -48,7 +53,7 @@
   private static final String FIELD_PATH_SEPARATOR = ",";
   private static final String FIELD_PATH_SEPARATOR_REGEX = ",";
   private static final String FIELD_SEPARATOR_REGEX = "\\.";
-  
+
   private FieldMaskUtil() {}
 
   /**
@@ -78,19 +83,17 @@
    */
   public static FieldMask fromString(String value) {
     // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
-    return fromStringList(
-        null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+    return fromStringList(null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
 
   /**
    * Parses from a string to a FieldMask and validates all field paths.
-   * 
+   *
    * @throws IllegalArgumentException if any of the field path is invalid.
    */
   public static FieldMask fromString(Class<? extends Message> type, String value) {
     // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
-    return fromStringList(
-        type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+    return fromStringList(type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
 
   /**
@@ -99,8 +102,7 @@
    * @throws IllegalArgumentException if any of the field path is not valid.
    */
   // TODO(xiaofeng): Consider renaming fromStrings()
-  public static FieldMask fromStringList(
-      Class<? extends Message> type, Iterable<String> paths) {
+  public static FieldMask fromStringList(Class<? extends Message> type, Iterable<String> paths) {
     FieldMask.Builder builder = FieldMask.newBuilder();
     for (String path : paths) {
       if (path.isEmpty()) {
@@ -108,8 +110,7 @@
         continue;
       }
       if (type != null && !isValid(type, path)) {
-        throw new IllegalArgumentException(
-            path + " is not a valid path for " + type);
+        throw new IllegalArgumentException(path + " is not a valid path for " + type);
       }
       builder.addPaths(path);
     }
@@ -146,15 +147,45 @@
   }
 
   /**
+   * Converts a field mask to a Proto3 JSON string, that is converting from snake case to camel
+   * case and joining all paths into one string with commas.
+   */
+  public static String toJsonString(FieldMask fieldMask) {
+    List<String> paths = new ArrayList<String>(fieldMask.getPathsCount());
+    for (String path : fieldMask.getPathsList()) {
+      if (path.isEmpty()) {
+        continue;
+      }
+      paths.add(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, path));
+    }
+    return Joiner.on(FIELD_PATH_SEPARATOR).join(paths);
+  }
+
+  /**
+   * Converts a field mask from a Proto3 JSON string, that is splitting the paths along commas and
+   * converting from camel case to snake case.
+   */
+  public static FieldMask fromJsonString(String value) {
+    Iterable<String> paths = Splitter.on(FIELD_PATH_SEPARATOR).split(value);
+    FieldMask.Builder builder = FieldMask.newBuilder();
+    for (String path : paths) {
+      if (path.isEmpty()) {
+        continue;
+      }
+      builder.addPaths(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, path));
+    }
+    return builder.build();
+  }
+
+  /**
    * Checks whether paths in a given fields mask are valid.
    */
   public static boolean isValid(Class<? extends Message> type, FieldMask fieldMask) {
-    Descriptor descriptor =
-        Internal.getDefaultInstance(type).getDescriptorForType();
-    
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
     return isValid(descriptor, fieldMask);
   }
-  
+
   /**
    * Checks whether paths in a given fields mask are valid.
    */
@@ -171,9 +202,8 @@
    * Checks whether a given field path is valid.
    */
   public static boolean isValid(Class<? extends Message> type, String path) {
-    Descriptor descriptor =
-        Internal.getDefaultInstance(type).getDescriptorForType();
-    
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
     return isValid(descriptor, path);
   }
 
@@ -193,8 +223,7 @@
       if (field == null) {
         return false;
       }
-      if (!field.isRepeated()
-          && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+      if (!field.isRepeated() && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
         descriptor = field.getMessageType();
       } else {
         descriptor = null;
@@ -202,7 +231,7 @@
     }
     return true;
   }
-  
+
   /**
    * Converts a FieldMask to its canonical form. In the canonical form of a
    * FieldMask, all field paths are sorted alphabetically and redundant field
@@ -211,14 +240,19 @@
   public static FieldMask normalize(FieldMask mask) {
     return new FieldMaskTree(mask).toFieldMask();
   }
-  
+
   /**
-   * Creates an union of two FieldMasks.
+   * Creates a union of two or more FieldMasks.
    */
-  public static FieldMask union(FieldMask mask1, FieldMask mask2) {
-    return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).toFieldMask();
+  public static FieldMask union(
+      FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) {
+    FieldMaskTree maskTree = new FieldMaskTree(firstMask).mergeFromFieldMask(secondMask);
+    for (FieldMask mask : otherMasks) {
+      maskTree.mergeFromFieldMask(mask);
+    }
+    return maskTree.toFieldMask();
   }
-  
+
   /**
    * Calculates the intersection of two FieldMasks.
    */
@@ -237,13 +271,16 @@
   public static final class MergeOptions {
     private boolean replaceMessageFields = false;
     private boolean replaceRepeatedFields = false;
+    // TODO(b/28277137): change the default behavior to always replace primitive fields after
+    // fixing all failing TAP tests.
+    private boolean replacePrimitiveFields = false;
 
     /**
      * Whether to replace message fields (i.e., discard existing content in
      * destination message fields) when merging.
      * Default behavior is to merge the source message field into the
      * destination message field.
-     */ 
+     */
     public boolean replaceMessageFields() {
       return replaceMessageFields;
     }
@@ -257,29 +294,52 @@
     public boolean replaceRepeatedFields() {
       return replaceRepeatedFields;
     }
-    
-    public void setReplaceMessageFields(boolean value) {
-      replaceMessageFields = value;
+
+    /**
+     * Whether to replace primitive (non-repeated and non-message) fields in
+     * destination message fields with the source primitive fields (i.e., if the
+     * field is set in the source, the value is copied to the
+     * destination; if the field is unset in the source, the field is cleared
+     * from the destination) when merging.
+     *
+     * <p>Default behavior is to always set the value of the source primitive
+     * field to the destination primitive field, and if the source field is
+     * unset, the default value of the source field is copied to the
+     * destination.
+     */
+    public boolean replacePrimitiveFields() {
+      return replacePrimitiveFields;
     }
 
-    public void setReplaceRepeatedFields(boolean value) {
+    public MergeOptions setReplaceMessageFields(boolean value) {
+      replaceMessageFields = value;
+      return this;
+    }
+
+    public MergeOptions setReplaceRepeatedFields(boolean value) {
       replaceRepeatedFields = value;
+      return this;
+    }
+
+    public MergeOptions setReplacePrimitiveFields(boolean value) {
+      replacePrimitiveFields = value;
+      return this;
     }
   }
-  
+
   /**
-   * Merges fields specified by a FieldMask from one message to another.
+   * Merges fields specified by a FieldMask from one message to another with the
+   * specified merge options.
    */
-  public static void merge(FieldMask mask, Message source,
-      Message.Builder destination, MergeOptions options) {
+  public static void merge(
+      FieldMask mask, Message source, Message.Builder destination, MergeOptions options) {
     new FieldMaskTree(mask).merge(source, destination, options);
   }
 
   /**
    * Merges fields specified by a FieldMask from one message to another.
    */
-  public static void merge(FieldMask mask, Message source,
-      Message.Builder destination) {
+  public static void merge(FieldMask mask, Message source, Message.Builder destination) {
     merge(mask, source, destination, new MergeOptions());
   }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index d13ff0e..7f69ee6 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -30,10 +30,13 @@
 
 package com.google.protobuf.util;
 
+import com.google.common.base.Preconditions;
 import com.google.common.io.BaseEncoding;
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
+import com.google.gson.JsonIOException;
 import com.google.gson.JsonNull;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
@@ -48,6 +51,7 @@
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.DoubleValue;
 import com.google.protobuf.Duration;
 import com.google.protobuf.DynamicMessage;
@@ -59,13 +63,13 @@
 import com.google.protobuf.ListValue;
 import com.google.protobuf.Message;
 import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.NullValue;
 import com.google.protobuf.StringValue;
 import com.google.protobuf.Struct;
 import com.google.protobuf.Timestamp;
 import com.google.protobuf.UInt32Value;
 import com.google.protobuf.UInt64Value;
 import com.google.protobuf.Value;
-
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
@@ -91,46 +95,70 @@
  * as well.
  */
 public class JsonFormat {
-  private static final Logger logger =
-      Logger.getLogger(JsonFormat.class.getName());
+  private static final Logger logger = Logger.getLogger(JsonFormat.class.getName());
 
   private JsonFormat() {}
-  
+
   /**
    * Creates a {@link Printer} with default configurations.
    */
   public static Printer printer() {
-    return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
+    return new Printer(
+        TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
+        false, false, false);
   }
-  
+
   /**
    * A Printer converts protobuf message to JSON format.
    */
   public static class Printer {
     private final TypeRegistry registry;
-    private final boolean includingDefaultValueFields;
+    // NOTE: There are 3 states for these *defaultValueFields variables:
+    // 1) Default - alwaysOutput is false & including is empty set. Fields only output if they are
+    //    set to non-default values.
+    // 2) No-args includingDefaultValueFields() called - alwaysOutput is true & including is
+    //    irrelevant (but set to empty set). All fields are output regardless of their values.
+    // 3) includingDefaultValueFields(Set<FieldDescriptor>) called - alwaysOutput is false &
+    //    including is set to the specified set. Fields in that set are always output & fields not
+    //    in that set are only output if set to non-default values.
+    private boolean alwaysOutputDefaultValueFields;
+    private Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
+    private final boolean omittingInsignificantWhitespace;
+    private final boolean printingEnumsAsInts;
 
     private Printer(
         TypeRegistry registry,
-        boolean includingDefaultValueFields,
-        boolean preservingProtoFieldNames) {
+        boolean alwaysOutputDefaultValueFields,
+        Set<FieldDescriptor> includingDefaultValueFields,
+        boolean preservingProtoFieldNames,
+        boolean omittingInsignificantWhitespace,
+        boolean printingEnumsAsInts) {
       this.registry = registry;
+      this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
+      this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
+      this.printingEnumsAsInts = printingEnumsAsInts;
     }
-    
+
     /**
      * Creates a new {@link Printer} using the given registry. The new Printer
      * clones all other configurations from the current {@link Printer}.
-     * 
+     *
      * @throws IllegalArgumentException if a registry is already set.
      */
     public Printer usingTypeRegistry(TypeRegistry registry) {
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames);
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          includingDefaultValueFields,
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
     }
 
     /**
@@ -140,7 +168,66 @@
      * {@link Printer}.
      */
     public Printer includingDefaultValueFields() {
-      return new Printer(registry, true, preservingProtoFieldNames);
+      checkUnsetIncludingDefaultValueFields();
+      return new Printer(
+          registry,
+          true,
+          Collections.<FieldDescriptor>emptySet(),
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
+    }
+
+    /**
+     * Creates a new {@link Printer} that will print enum field values as integers instead of as
+     * string.
+     * The new Printer clones all other configurations from the current
+     * {@link Printer}.
+     */
+    public Printer printingEnumsAsInts() {
+      checkUnsetPrintingEnumsAsInts();
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          Collections.<FieldDescriptor>emptySet(),
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          true);
+    }
+
+    private void checkUnsetPrintingEnumsAsInts() {
+      if (printingEnumsAsInts) {
+        throw new IllegalStateException("JsonFormat printingEnumsAsInts has already been set.");
+      }
+    }
+
+    /**
+     * Creates a new {@link Printer} that will also print default-valued fields if their
+     * FieldDescriptors are found in the supplied set. Empty repeated fields and map fields will be
+     * printed as well, if they match. The new Printer clones all other configurations from the
+     * current {@link Printer}. Call includingDefaultValueFields() with no args to unconditionally
+     * output all fields.
+     */
+    public Printer includingDefaultValueFields(Set<FieldDescriptor> fieldsToAlwaysOutput) {
+      Preconditions.checkArgument(
+          null != fieldsToAlwaysOutput && !fieldsToAlwaysOutput.isEmpty(),
+          "Non-empty Set must be supplied for includingDefaultValueFields.");
+
+      checkUnsetIncludingDefaultValueFields();
+      return new Printer(
+          registry,
+          false,
+          fieldsToAlwaysOutput,
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
+    }
+
+    private void checkUnsetIncludingDefaultValueFields() {
+      if (alwaysOutputDefaultValueFields || !includingDefaultValueFields.isEmpty()) {
+        throw new IllegalStateException(
+            "JsonFormat includingDefaultValueFields has already been set.");
+      }
     }
 
     /**
@@ -150,30 +237,69 @@
      * current {@link Printer}.
      */
     public Printer preservingProtoFieldNames() {
-      return new Printer(registry, includingDefaultValueFields, true);
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          includingDefaultValueFields,
+          true,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
     }
-    
+
+
+    /**
+     * Create a new {@link Printer} that will omit all insignificant whitespace in the JSON output.
+     * This new Printer clones all other configurations from the current Printer. Insignificant
+     * whitespace is defined by the JSON spec as whitespace that appear between JSON structural
+     * elements:
+     *
+     * <pre>
+     * ws = *(
+     * %x20 /              ; Space
+     * %x09 /              ; Horizontal tab
+     * %x0A /              ; Line feed or New line
+     * %x0D )              ; Carriage return
+     * </pre>
+     *
+     * See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/html/rfc7159</a>
+     * current {@link Printer}.
+     */
+    public Printer omittingInsignificantWhitespace() {
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          includingDefaultValueFields,
+          preservingProtoFieldNames,
+          true,
+          printingEnumsAsInts);
+    }
+
     /**
      * Converts a protobuf message to JSON format.
-     * 
-     * @throws InvalidProtocolBufferException if the message contains Any types
-     *         that can't be resolved.
+     *
+     * @throws InvalidProtocolBufferException if the message contains Any types that can't be
+     *     resolved.
      * @throws IOException if writing to the output fails.
      */
-    public void appendTo(MessageOrBuilder message, Appendable output)
-        throws IOException {
+    public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
+      new PrinterImpl(
+              registry,
+              alwaysOutputDefaultValueFields,
+              includingDefaultValueFields,
+              preservingProtoFieldNames,
+              output,
+              omittingInsignificantWhitespace,
+              printingEnumsAsInts)
           .print(message);
     }
 
     /**
      * Converts a protobuf message to JSON format. Throws exceptions if there
-     * are unknown Any types in the message. 
+     * are unknown Any types in the message.
      */
-    public String print(MessageOrBuilder message)
-        throws InvalidProtocolBufferException {
+    public String print(MessageOrBuilder message) throws InvalidProtocolBufferException {
       try {
         StringBuilder builder = new StringBuilder();
         appendTo(message, builder);
@@ -191,57 +317,75 @@
    * Creates a {@link Parser} with default configuration.
    */
   public static Parser parser() {
-    return new Parser(TypeRegistry.getEmptyTypeRegistry());
+    return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT_RECURSION_LIMIT);
   }
-  
+
   /**
    * A Parser parses JSON to protobuf message.
    */
   public static class Parser {
     private final TypeRegistry registry;
-    
-    private Parser(TypeRegistry registry) {
-      this.registry = registry; 
+    private final boolean ignoringUnknownFields;
+    private final int recursionLimit;
+
+    // The default parsing recursion limit is aligned with the proto binary parser.
+    private static final int DEFAULT_RECURSION_LIMIT = 100;
+
+    private Parser(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
+      this.registry = registry;
+      this.ignoringUnknownFields = ignoreUnknownFields;
+      this.recursionLimit = recursionLimit;
     }
-    
+
     /**
      * Creates a new {@link Parser} using the given registry. The new Parser
      * clones all other configurations from this Parser.
-     * 
+     *
      * @throws IllegalArgumentException if a registry is already set.
      */
     public Parser usingTypeRegistry(TypeRegistry registry) {
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Parser(registry);
+      return new Parser(registry, ignoringUnknownFields, recursionLimit);
     }
-    
+
+    /**
+     * Creates a new {@link Parser} configured to not throw an exception when an unknown field is
+     * encountered. The new Parser clones all other configurations from this Parser.
+     */
+    public Parser ignoringUnknownFields() {
+      return new Parser(this.registry, true, recursionLimit);
+    }
+
     /**
      * Parses from JSON into a protobuf message.
-     * 
+     *
      * @throws InvalidProtocolBufferException if the input is not valid JSON
      *         format or there are unknown fields in the input.
      */
-    public void merge(String json, Message.Builder builder)
-        throws InvalidProtocolBufferException {
+    public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
     }
-    
+
     /**
      * Parses from JSON into a protobuf message.
-     * 
+     *
      * @throws InvalidProtocolBufferException if the input is not valid JSON
      *         format or there are unknown fields in the input.
      * @throws IOException if reading from the input throws.
      */
-    public void merge(Reader json, Message.Builder builder)
-        throws IOException {
+    public void merge(Reader json, Message.Builder builder) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
+    }
+
+    // For testing only.
+    Parser usingRecursionLimit(int recursionLimit) {
+      return new Parser(registry, ignoringUnknownFields, recursionLimit);
     }
   }
 
@@ -254,8 +398,8 @@
    */
   public static class TypeRegistry {
     private static class EmptyTypeRegistryHolder {
-      private static final TypeRegistry EMPTY = new TypeRegistry(
-          Collections.<String, Descriptor>emptyMap());
+      private static final TypeRegistry EMPTY =
+          new TypeRegistry(Collections.<String, Descriptor>emptyMap());
     }
 
     public static TypeRegistry getEmptyTypeRegistry() {
@@ -292,8 +436,7 @@
        */
       public Builder add(Descriptor messageType) {
         if (types == null) {
-          throw new IllegalStateException(
-              "A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
         }
         addFile(messageType.getFile());
         return this;
@@ -305,8 +448,7 @@
        */
       public Builder add(Iterable<Descriptor> messageTypes) {
         if (types == null) {
-          throw new IllegalStateException(
-              "A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
         }
         for (Descriptor type : messageTypes) {
           addFile(type.getFile());
@@ -344,8 +486,7 @@
         }
 
         if (types.containsKey(message.getFullName())) {
-          logger.warning("Type " + message.getFullName()
-              + " is added multiple times.");
+          logger.warning("Type " + message.getFullName() + " is added multiple times.");
           return;
         }
 
@@ -353,48 +494,80 @@
       }
 
       private final Set<String> files = new HashSet<String>();
-      private Map<String, Descriptor> types =
-          new HashMap<String, Descriptor>();
+      private Map<String, Descriptor> types = new HashMap<String, Descriptor>();
     }
   }
 
   /**
+   * An interface for json formatting that can be used in
+   * combination with the omittingInsignificantWhitespace() method
+   */
+  interface TextGenerator {
+    void indent();
+
+    void outdent();
+
+    void print(final CharSequence text) throws IOException;
+  }
+
+  /**
+   * Format the json without indentation
+   */
+  private static final class CompactTextGenerator implements TextGenerator {
+    private final Appendable output;
+
+    private CompactTextGenerator(final Appendable output) {
+      this.output = output;
+    }
+
+    /** ignored by compact printer */
+    @Override
+    public void indent() {}
+
+    /** ignored by compact printer */
+    @Override
+    public void outdent() {}
+
+    /** Print text to the output stream. */
+    @Override
+    public void print(final CharSequence text) throws IOException {
+      output.append(text);
+    }
+  }
+  /**
    * A TextGenerator adds indentation when writing formatted text.
    */
-  private static final class TextGenerator {
+  private static final class PrettyTextGenerator implements TextGenerator {
     private final Appendable output;
     private final StringBuilder indent = new StringBuilder();
     private boolean atStartOfLine = true;
 
-    private TextGenerator(final Appendable output) {
+    private PrettyTextGenerator(final Appendable output) {
       this.output = output;
     }
 
     /**
-     * Indent text by two spaces.  After calling Indent(), two spaces will be
-     * inserted at the beginning of each line of text.  Indent() may be called
-     * multiple times to produce deeper indents.
+     * Indent text by two spaces. After calling Indent(), two spaces will be inserted at the
+     * beginning of each line of text. Indent() may be called multiple times to produce deeper
+     * indents.
      */
+    @Override
     public void indent() {
       indent.append("  ");
     }
 
-    /**
-     * Reduces the current indent level by two spaces, or crashes if the indent
-     * level is zero.
-     */
+    /** Reduces the current indent level by two spaces, or crashes if the indent level is zero. */
+    @Override
     public void outdent() {
       final int length = indent.length();
       if (length < 2) {
-        throw new IllegalArgumentException(
-            " Outdent() without matching Indent().");
+        throw new IllegalArgumentException(" Outdent() without matching Indent().");
       }
       indent.delete(length - 2, length);
     }
 
-    /**
-     * Print text to the output stream.
-     */
+    /** Print text to the output stream. */
+    @Override
     public void print(final CharSequence text) throws IOException {
       final int size = text.length();
       int pos = 0;
@@ -426,68 +599,82 @@
    */
   private static final class PrinterImpl {
     private final TypeRegistry registry;
-    private final boolean includingDefaultValueFields;
+    private final boolean alwaysOutputDefaultValueFields;
+    private final Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
+    private final boolean printingEnumsAsInts;
     private final TextGenerator generator;
     // We use Gson to help handle string escapes.
     private final Gson gson;
+    private final CharSequence blankOrSpace;
+    private final CharSequence blankOrNewLine;
 
     private static class GsonHolder {
-      private static final Gson DEFAULT_GSON = new Gson();
+      private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
     }
 
     PrinterImpl(
         TypeRegistry registry,
-        boolean includingDefaultValueFields,
+        boolean alwaysOutputDefaultValueFields,
+        Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
-        Appendable jsonOutput) {
+        Appendable jsonOutput,
+        boolean omittingInsignificantWhitespace,
+        boolean printingEnumsAsInts) {
       this.registry = registry;
+      this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
-      this.generator = new TextGenerator(jsonOutput);
+      this.printingEnumsAsInts = printingEnumsAsInts;
       this.gson = GsonHolder.DEFAULT_GSON;
+      // json format related properties, determined by printerType
+      if (omittingInsignificantWhitespace) {
+        this.generator = new CompactTextGenerator(jsonOutput);
+        this.blankOrSpace = "";
+        this.blankOrNewLine = "";
+      } else {
+        this.generator = new PrettyTextGenerator(jsonOutput);
+        this.blankOrSpace = " ";
+        this.blankOrNewLine = "\n";
+      }
     }
 
     void print(MessageOrBuilder message) throws IOException {
-      WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get(
-          message.getDescriptorForType().getFullName());
+      WellKnownTypePrinter specialPrinter =
+          wellKnownTypePrinters.get(message.getDescriptorForType().getFullName());
       if (specialPrinter != null) {
         specialPrinter.print(this, message);
         return;
       }
       print(message, null);
     }
-    
+
     private interface WellKnownTypePrinter {
-      void print(PrinterImpl printer, MessageOrBuilder message)
-          throws IOException;
+      void print(PrinterImpl printer, MessageOrBuilder message) throws IOException;
     }
-    
-    private static final Map<String, WellKnownTypePrinter>
-    wellKnownTypePrinters = buildWellKnownTypePrinters();
-    
-    private static Map<String, WellKnownTypePrinter>
-    buildWellKnownTypePrinters() {
-      Map<String, WellKnownTypePrinter> printers =
-          new HashMap<String, WellKnownTypePrinter>();
+
+    private static final Map<String, WellKnownTypePrinter> wellKnownTypePrinters =
+        buildWellKnownTypePrinters();
+
+    private static Map<String, WellKnownTypePrinter> buildWellKnownTypePrinters() {
+      Map<String, WellKnownTypePrinter> printers = new HashMap<String, WellKnownTypePrinter>();
       // Special-case Any.
-      printers.put(Any.getDescriptor().getFullName(),
+      printers.put(
+          Any.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printAny(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printAny(message);
+            }
+          });
       // Special-case wrapper types.
-      WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printWrapper(message);
-          
-        }
-      };
+      WellKnownTypePrinter wrappersPrinter =
+          new WellKnownTypePrinter() {
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printWrapper(message);
+            }
+          };
       printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -498,70 +685,75 @@
       printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
       // Special-case Timestamp.
-      printers.put(Timestamp.getDescriptor().getFullName(),
+      printers.put(
+          Timestamp.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printTimestamp(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printTimestamp(message);
+            }
+          });
       // Special-case Duration.
-      printers.put(Duration.getDescriptor().getFullName(),
+      printers.put(
+          Duration.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printDuration(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printDuration(message);
+            }
+          });
       // Special-case FieldMask.
-      printers.put(FieldMask.getDescriptor().getFullName(),
+      printers.put(
+          FieldMask.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printFieldMask(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printFieldMask(message);
+            }
+          });
       // Special-case Struct.
-      printers.put(Struct.getDescriptor().getFullName(),
+      printers.put(
+          Struct.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printStruct(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printStruct(message);
+            }
+          });
       // Special-case Value.
-      printers.put(Value.getDescriptor().getFullName(),
+      printers.put(
+          Value.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printValue(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printValue(message);
+            }
+          });
       // Special-case ListValue.
-      printers.put(ListValue.getDescriptor().getFullName(),
+      printers.put(
+          ListValue.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printListValue(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printListValue(message);
+            }
+          });
       return printers;
     }
-    
+
     /** Prints google.protobuf.Any */
     private void printAny(MessageOrBuilder message) throws IOException {
+      if (Any.getDefaultInstance().equals(message)) {
+        generator.print("{}");
+        return;
+      }
       Descriptor descriptor = message.getDescriptorForType();
       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
       FieldDescriptor valueField = descriptor.findFieldByName("value");
       // Validates type of the message. Note that we can't just cast the message
-      // to com.google.protobuf.Any because it might be a DynamicMessage. 
-      if (typeUrlField == null || valueField == null
+      // to com.google.protobuf.Any because it might be a DynamicMessage.
+      if (typeUrlField == null
+          || valueField == null
           || typeUrlField.getType() != FieldDescriptor.Type.STRING
           || valueField.getType() != FieldDescriptor.Type.BYTES) {
         throw new InvalidProtocolBufferException("Invalid Any type.");
@@ -570,22 +762,21 @@
       String typeName = getTypeName(typeUrl);
       Descriptor type = registry.find(typeName);
       if (type == null) {
-        throw new InvalidProtocolBufferException(
-            "Cannot find type for url: " + typeUrl);
+        throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
       }
       ByteString content = (ByteString) message.getField(valueField);
-      Message contentMessage = DynamicMessage.getDefaultInstance(type)
-          .getParserForType().parseFrom(content);
+      Message contentMessage =
+          DynamicMessage.getDefaultInstance(type).getParserForType().parseFrom(content);
       WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
       if (printer != null) {
         // If the type is one of the well-known types, we use a special
         // formatting.
-        generator.print("{\n");
+        generator.print("{" + blankOrNewLine);
         generator.indent();
-        generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n");
-        generator.print("\"value\": ");
+        generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl) + "," + blankOrNewLine);
+        generator.print("\"value\":" + blankOrSpace);
         printer.print(this, contentMessage);
-        generator.print("\n");
+        generator.print(blankOrNewLine);
         generator.outdent();
         generator.print("}");
       } else {
@@ -593,7 +784,7 @@
         print(contentMessage, typeUrl);
       }
     }
-    
+
     /** Prints wrapper types (e.g., google.protobuf.Int32Value) */
     private void printWrapper(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -605,7 +796,7 @@
       // the whole message.
       printSingleFieldValue(valueField, message.getField(valueField));
     }
-    
+
     private ByteString toByteString(MessageOrBuilder message) {
       if (message instanceof Message) {
         return ((Message) message).toByteString();
@@ -613,26 +804,25 @@
         return ((Message.Builder) message).build().toByteString();
       }
     }
-    
+
     /** Prints google.protobuf.Timestamp */
     private void printTimestamp(MessageOrBuilder message) throws IOException {
       Timestamp value = Timestamp.parseFrom(toByteString(message));
-      generator.print("\"" + TimeUtil.toString(value) + "\"");
+      generator.print("\"" + Timestamps.toString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.Duration */
     private void printDuration(MessageOrBuilder message) throws IOException {
       Duration value = Duration.parseFrom(toByteString(message));
-      generator.print("\"" + TimeUtil.toString(value) + "\"");
-      
+      generator.print("\"" + Durations.toString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.FieldMask */
     private void printFieldMask(MessageOrBuilder message) throws IOException {
       FieldMask value = FieldMask.parseFrom(toByteString(message));
-      generator.print("\"" + FieldMaskUtil.toString(value) + "\"");
+      generator.print("\"" + FieldMaskUtil.toJsonString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.Struct */
     private void printStruct(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -643,7 +833,7 @@
       // Struct is formatted as a map object.
       printMapFieldValue(field, message.getField(field));
     }
-    
+
     /** Prints google.protobuf.Value */
     private void printValue(MessageOrBuilder message) throws IOException {
       // For a Value message, only the value of the field is formatted.
@@ -662,7 +852,7 @@
         printSingleFieldValue(entry.getKey(), entry.getValue());
       }
     }
-    
+
     /** Prints google.protobuf.ListValue */
     private void printListValue(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -674,28 +864,36 @@
     }
 
     /** Prints a regular message with an optional type URL. */
-    private void print(MessageOrBuilder message, String typeUrl)
-        throws IOException {
-      generator.print("{\n");
+    private void print(MessageOrBuilder message, String typeUrl) throws IOException {
+      generator.print("{" + blankOrNewLine);
       generator.indent();
 
       boolean printedField = false;
       if (typeUrl != null) {
-        generator.print("\"@type\": " + gson.toJson(typeUrl));
+        generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl));
         printedField = true;
       }
       Map<FieldDescriptor, Object> fieldsToPrint = null;
-      if (includingDefaultValueFields) {
-        fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
+      if (alwaysOutputDefaultValueFields || !includingDefaultValueFields.isEmpty()) {
+        fieldsToPrint = new TreeMap<FieldDescriptor, Object>(message.getAllFields());
         for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
-          if (field.isOptional()
-              && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
-              && !message.hasField(field)) {
-            // Always skip empty optional message fields. If not we will recurse indefinitely if
-            // a message has itself as a sub-field.
-            continue;
+          if (field.isOptional()) {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
+                && !message.hasField(field)) {
+              // Always skip empty optional message fields. If not we will recurse indefinitely if
+              // a message has itself as a sub-field.
+              continue;
+            }
+            OneofDescriptor oneof = field.getContainingOneof();
+            if (oneof != null && !message.hasField(field)) {
+              // Skip all oneof fields except the one that is actually set
+              continue;
+            }
           }
-          fieldsToPrint.put(field, message.getField(field));
+          if (!fieldsToPrint.containsKey(field)
+              && (alwaysOutputDefaultValueFields || includingDefaultValueFields.contains(field))) {
+            fieldsToPrint.put(field, message.getField(field));
+          }
         }
       } else {
         fieldsToPrint = message.getAllFields();
@@ -703,27 +901,26 @@
       for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) {
         if (printedField) {
           // Add line-endings for the previous field.
-          generator.print(",\n");
+          generator.print("," + blankOrNewLine);
         } else {
           printedField = true;
         }
         printField(field.getKey(), field.getValue());
       }
-      
+
       // Add line-endings for the last field.
       if (printedField) {
-        generator.print("\n");
+        generator.print(blankOrNewLine);
       }
       generator.outdent();
       generator.print("}");
     }
 
-    private void printField(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printField(FieldDescriptor field, Object value) throws IOException {
       if (preservingProtoFieldNames) {
-        generator.print("\"" + field.getName() + "\": ");
+        generator.print("\"" + field.getName() + "\":" + blankOrSpace);
       } else {
-        generator.print("\"" + field.getJsonName() + "\": ");
+        generator.print("\"" + field.getJsonName() + "\":" + blankOrSpace);
       }
       if (field.isMapField()) {
         printMapFieldValue(field, value);
@@ -733,15 +930,14 @@
         printSingleFieldValue(field, value);
       }
     }
-    
+
     @SuppressWarnings("rawtypes")
-    private void printRepeatedFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printRepeatedFieldValue(FieldDescriptor field, Object value) throws IOException {
       generator.print("[");
       boolean printedElement = false;
       for (Object element : (List) value) {
         if (printedElement) {
-          generator.print(", ");
+          generator.print("," + blankOrSpace);
         } else {
           printedElement = true;
         }
@@ -749,17 +945,16 @@
       }
       generator.print("]");
     }
-    
+
     @SuppressWarnings("rawtypes")
-    private void printMapFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printMapFieldValue(FieldDescriptor field, Object value) throws IOException {
       Descriptor type = field.getMessageType();
       FieldDescriptor keyField = type.findFieldByName("key");
       FieldDescriptor valueField = type.findFieldByName("value");
       if (keyField == null || valueField == null) {
         throw new InvalidProtocolBufferException("Invalid map field.");
       }
-      generator.print("{\n");
+      generator.print("{" + blankOrNewLine);
       generator.indent();
       boolean printedElement = false;
       for (Object element : (List) value) {
@@ -767,36 +962,35 @@
         Object entryKey = entry.getField(keyField);
         Object entryValue = entry.getField(valueField);
         if (printedElement) {
-          generator.print(",\n");
+          generator.print("," + blankOrNewLine);
         } else {
           printedElement = true;
         }
         // Key fields are always double-quoted.
         printSingleFieldValue(keyField, entryKey, true);
-        generator.print(": ");
+        generator.print(":" + blankOrSpace);
         printSingleFieldValue(valueField, entryValue);
       }
       if (printedElement) {
-        generator.print("\n");
+        generator.print(blankOrNewLine);
       }
       generator.outdent();
       generator.print("}");
     }
-    
-    private void printSingleFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+
+    private void printSingleFieldValue(FieldDescriptor field, Object value) throws IOException {
       printSingleFieldValue(field, value, false);
     }
 
     /**
      * Prints a field's value in JSON format.
-     * 
+     *
      * @param alwaysWithQuotes whether to always add double-quotes to primitive
      *        types.
      */
     private void printSingleFieldValue(
-        final FieldDescriptor field, final Object value,
-        boolean alwaysWithQuotes) throws IOException {
+        final FieldDescriptor field, final Object value, boolean alwaysWithQuotes)
+        throws IOException {
       switch (field.getType()) {
         case INT32:
         case SINT32:
@@ -850,7 +1044,7 @@
             }
           }
           break;
-          
+
         case DOUBLE:
           Double doubleValue = (Double) value;
           if (doubleValue.isNaN()) {
@@ -894,15 +1088,13 @@
 
         case BYTES:
           generator.print("\"");
-          generator.print(
-              BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
+          generator.print(BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
           generator.print("\"");
           break;
 
         case ENUM:
           // Special-case google.protobuf.NullValue (it's an Enum).
-          if (field.getEnumType().getFullName().equals(
-                  "google.protobuf.NullValue")) {
+          if (field.getEnumType().getFullName().equals("google.protobuf.NullValue")) {
             // No matter what value it contains, we always print it as "null".
             if (alwaysWithQuotes) {
               generator.print("\"");
@@ -912,12 +1104,10 @@
               generator.print("\"");
             }
           } else {
-            if (((EnumValueDescriptor) value).getIndex() == -1) {
-              generator.print(
-                  String.valueOf(((EnumValueDescriptor) value).getNumber()));
+            if (printingEnumsAsInts || ((EnumValueDescriptor) value).getIndex() == -1) {
+              generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
             } else {
-              generator.print(
-                  "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+              generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");
             }
           }
           break;
@@ -946,41 +1136,54 @@
     } else {
       // Pull off the most-significant bit so that BigInteger doesn't think
       // the number is negative, then set it again using setBit().
-      return BigInteger.valueOf(value & Long.MAX_VALUE)
-                       .setBit(Long.SIZE - 1).toString();
+      return BigInteger.valueOf(value & Long.MAX_VALUE).setBit(Long.SIZE - 1).toString();
     }
   }
-  
-  private static final String TYPE_URL_PREFIX = "type.googleapis.com";
-  
-  private static String getTypeName(String typeUrl)
-      throws InvalidProtocolBufferException {
+
+  private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException {
     String[] parts = typeUrl.split("/");
-    if (parts.length != 2 || !parts[0].equals(TYPE_URL_PREFIX)) {
-      throw new InvalidProtocolBufferException(
-          "Invalid type url found: " + typeUrl);
+    if (parts.length == 1) {
+      throw new InvalidProtocolBufferException("Invalid type url found: " + typeUrl);
     }
-    return parts[1];
+    return parts[parts.length - 1];
   }
-  
+
   private static class ParserImpl {
     private final TypeRegistry registry;
     private final JsonParser jsonParser;
-    
-    ParserImpl(TypeRegistry registry) {
+    private final boolean ignoringUnknownFields;
+    private final int recursionLimit;
+    private int currentDepth;
+
+    ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
       this.registry = registry;
+      this.ignoringUnknownFields = ignoreUnknownFields;
       this.jsonParser = new JsonParser();
+      this.recursionLimit = recursionLimit;
+      this.currentDepth = 0;
     }
-    
-    void merge(Reader json, Message.Builder builder)
-        throws IOException {
-      JsonReader reader = new JsonReader(json);
-      reader.setLenient(false);
-      merge(jsonParser.parse(reader), builder);
+
+    void merge(Reader json, Message.Builder builder) throws IOException {
+      try {
+        JsonReader reader = new JsonReader(json);
+        reader.setLenient(false);
+        merge(jsonParser.parse(reader), builder);
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (JsonIOException e) {
+        // Unwrap IOException.
+        if (e.getCause() instanceof IOException) {
+          throw (IOException) e.getCause();
+        } else {
+          throw new InvalidProtocolBufferException(e.getMessage());
+        }
+      } catch (Exception e) {
+        // We convert all exceptions from JSON parsing to our own exceptions.
+        throw new InvalidProtocolBufferException(e.getMessage());
+      }
     }
-    
-    void merge(String json, Message.Builder builder)
-        throws InvalidProtocolBufferException {
+
+    void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       try {
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.setLenient(false);
@@ -992,35 +1195,36 @@
         throw new InvalidProtocolBufferException(e.getMessage());
       }
     }
-    
+
     private interface WellKnownTypeParser {
       void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
           throws InvalidProtocolBufferException;
     }
-    
+
     private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers =
         buildWellKnownTypeParsers();
-    
-    private static Map<String, WellKnownTypeParser>
-    buildWellKnownTypeParsers() {
-      Map<String, WellKnownTypeParser> parsers =
-          new HashMap<String, WellKnownTypeParser>();
+
+    private static Map<String, WellKnownTypeParser> buildWellKnownTypeParsers() {
+      Map<String, WellKnownTypeParser> parsers = new HashMap<String, WellKnownTypeParser>();
       // Special-case Any.
-      parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeAny(json, builder);
-        }
-      });
+      parsers.put(
+          Any.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeAny(json, builder);
+            }
+          });
       // Special-case wrapper types.
-      WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeWrapper(json, builder);
-        }
-      };
+      WellKnownTypeParser wrappersPrinter =
+          new WellKnownTypeParser() {
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeWrapper(json, builder);
+            }
+          };
       parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -1031,73 +1235,86 @@
       parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
       // Special-case Timestamp.
-      parsers.put(Timestamp.getDescriptor().getFullName(),
+      parsers.put(
+          Timestamp.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeTimestamp(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeTimestamp(json, builder);
+            }
+          });
       // Special-case Duration.
-      parsers.put(Duration.getDescriptor().getFullName(),
+      parsers.put(
+          Duration.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeDuration(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeDuration(json, builder);
+            }
+          });
       // Special-case FieldMask.
-      parsers.put(FieldMask.getDescriptor().getFullName(),
+      parsers.put(
+          FieldMask.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeFieldMask(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeFieldMask(json, builder);
+            }
+          });
       // Special-case Struct.
-      parsers.put(Struct.getDescriptor().getFullName(),
+      parsers.put(
+          Struct.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeStruct(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeStruct(json, builder);
+            }
+          });
+      // Special-case ListValue.
+      parsers.put(
+          ListValue.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeListValue(json, builder);
+            }
+          });
       // Special-case Value.
-      parsers.put(Value.getDescriptor().getFullName(),
+      parsers.put(
+          Value.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeValue(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeValue(json, builder);
+            }
+          });
       return parsers;
     }
-    
+
     private void merge(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
-      WellKnownTypeParser specialParser = wellKnownTypeParsers.get(
-          builder.getDescriptorForType().getFullName());
+      WellKnownTypeParser specialParser =
+          wellKnownTypeParsers.get(builder.getDescriptorForType().getFullName());
       if (specialParser != null) {
         specialParser.merge(this, json, builder);
         return;
       }
       mergeMessage(json, builder, false);
     }
-    
+
     // Maps from camel-case field names to FieldDescriptor.
     private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps =
         new HashMap<Descriptor, Map<String, FieldDescriptor>>();
-    
-    private Map<String, FieldDescriptor> getFieldNameMap(
-        Descriptor descriptor) {
+
+    private Map<String, FieldDescriptor> getFieldNameMap(Descriptor descriptor) {
       if (!fieldNameMaps.containsKey(descriptor)) {
-        Map<String, FieldDescriptor> fieldNameMap =
-            new HashMap<String, FieldDescriptor>();
+        Map<String, FieldDescriptor> fieldNameMap = new HashMap<String, FieldDescriptor>();
         for (FieldDescriptor field : descriptor.getFields()) {
           fieldNameMap.put(field.getName(), field);
           fieldNameMap.put(field.getJsonName(), field);
@@ -1107,64 +1324,67 @@
       }
       return fieldNameMaps.get(descriptor);
     }
-    
-    private void mergeMessage(JsonElement json, Message.Builder builder,
-        boolean skipTypeUrl) throws InvalidProtocolBufferException {
+
+    private void mergeMessage(JsonElement json, Message.Builder builder, boolean skipTypeUrl)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect message object but got: " + json);
+        throw new InvalidProtocolBufferException("Expect message object but got: " + json);
       }
       JsonObject object = (JsonObject) json;
-      Map<String, FieldDescriptor> fieldNameMap =
-          getFieldNameMap(builder.getDescriptorForType());
+      Map<String, FieldDescriptor> fieldNameMap = getFieldNameMap(builder.getDescriptorForType());
       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
         if (skipTypeUrl && entry.getKey().equals("@type")) {
           continue;
         }
         FieldDescriptor field = fieldNameMap.get(entry.getKey());
         if (field == null) {
+          if (ignoringUnknownFields) {
+            continue;
+          }
           throw new InvalidProtocolBufferException(
-              "Cannot find field: " + entry.getKey() + " in message "
-              + builder.getDescriptorForType().getFullName());
+              "Cannot find field: "
+                  + entry.getKey()
+                  + " in message "
+                  + builder.getDescriptorForType().getFullName());
         }
         mergeField(field, entry.getValue(), builder);
       }
     }
-    
+
     private void mergeAny(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor descriptor = builder.getDescriptorForType();
       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
       FieldDescriptor valueField = descriptor.findFieldByName("value");
       // Validates type of the message. Note that we can't just cast the message
-      // to com.google.protobuf.Any because it might be a DynamicMessage. 
-      if (typeUrlField == null || valueField == null
+      // to com.google.protobuf.Any because it might be a DynamicMessage.
+      if (typeUrlField == null
+          || valueField == null
           || typeUrlField.getType() != FieldDescriptor.Type.STRING
           || valueField.getType() != FieldDescriptor.Type.BYTES) {
         throw new InvalidProtocolBufferException("Invalid Any type.");
       }
-      
+
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect message object but got: " + json);
+        throw new InvalidProtocolBufferException("Expect message object but got: " + json);
       }
       JsonObject object = (JsonObject) json;
+      if (object.entrySet().isEmpty()) {
+        return; // builder never modified, so it will end up building the default instance of Any
+      }
       JsonElement typeUrlElement = object.get("@type");
       if (typeUrlElement == null) {
-        throw new InvalidProtocolBufferException(
-            "Missing type url when parsing: " + json);
+        throw new InvalidProtocolBufferException("Missing type url when parsing: " + json);
       }
       String typeUrl = typeUrlElement.getAsString();
       Descriptor contentType = registry.find(getTypeName(typeUrl));
       if (contentType == null) {
-        throw new InvalidProtocolBufferException(
-            "Cannot resolve type: " + typeUrl);
+        throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
       }
       builder.setField(typeUrlField, typeUrl);
       Message.Builder contentBuilder =
           DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
-      WellKnownTypeParser specialParser =
-          wellKnownTypeParsers.get(contentType.getFullName());
+      WellKnownTypeParser specialParser = wellKnownTypeParsers.get(contentType.getFullName());
       if (specialParser != null) {
         JsonElement value = object.get("value");
         if (value != null) {
@@ -1175,35 +1395,33 @@
       }
       builder.setField(valueField, contentBuilder.build().toByteString());
     }
-    
+
     private void mergeFieldMask(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
-      FieldMask value = FieldMaskUtil.fromString(json.getAsString());
+      FieldMask value = FieldMaskUtil.fromJsonString(json.getAsString());
       builder.mergeFrom(value.toByteString());
     }
-    
+
     private void mergeTimestamp(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       try {
-        Timestamp value = TimeUtil.parseTimestamp(json.getAsString());
+        Timestamp value = Timestamps.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException e) {
-        throw new InvalidProtocolBufferException(
-            "Failed to parse timestamp: " + json);
+        throw new InvalidProtocolBufferException("Failed to parse timestamp: " + json);
       }
     }
-    
+
     private void mergeDuration(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       try {
-        Duration value = TimeUtil.parseDuration(json.getAsString());
+        Duration value = Durations.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException e) {
-        throw new InvalidProtocolBufferException(
-            "Failed to parse duration: " + json);
+        throw new InvalidProtocolBufferException("Failed to parse duration: " + json);
       }
     }
-    
+
     private void mergeStruct(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor descriptor = builder.getDescriptorForType();
@@ -1213,21 +1431,28 @@
       }
       mergeMapField(field, json, builder);
     }
-    
+
+    private void mergeListValue(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor descriptor = builder.getDescriptorForType();
+      FieldDescriptor field = descriptor.findFieldByName("values");
+      if (field == null) {
+        throw new InvalidProtocolBufferException("Invalid ListValue type.");
+      }
+      mergeRepeatedField(field, json, builder);
+    }
+
     private void mergeValue(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor type = builder.getDescriptorForType();
       if (json instanceof JsonPrimitive) {
         JsonPrimitive primitive = (JsonPrimitive) json;
         if (primitive.isBoolean()) {
-          builder.setField(type.findFieldByName("bool_value"),
-              primitive.getAsBoolean());
+          builder.setField(type.findFieldByName("bool_value"), primitive.getAsBoolean());
         } else if (primitive.isNumber()) {
-          builder.setField(type.findFieldByName("number_value"),
-              primitive.getAsDouble());
+          builder.setField(type.findFieldByName("number_value"), primitive.getAsDouble());
         } else {
-          builder.setField(type.findFieldByName("string_value"),
-              primitive.getAsString());
+          builder.setField(type.findFieldByName("string_value"), primitive.getAsString());
         }
       } else if (json instanceof JsonObject) {
         FieldDescriptor field = type.findFieldByName("struct_value");
@@ -1237,28 +1462,28 @@
       } else if (json instanceof JsonArray) {
         FieldDescriptor field = type.findFieldByName("list_value");
         Message.Builder listBuilder = builder.newBuilderForField(field);
-        FieldDescriptor listField =
-            listBuilder.getDescriptorForType().findFieldByName("values");
-        mergeRepeatedField(listField, json, listBuilder);
+        merge(json, listBuilder);
         builder.setField(field, listBuilder.build());
+      } else if (json instanceof JsonNull) {
+        builder.setField(
+            type.findFieldByName("null_value"), NullValue.NULL_VALUE.getValueDescriptor());
       } else {
         throw new IllegalStateException("Unexpected json data: " + json);
       }
     }
-    
+
     private void mergeWrapper(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor type = builder.getDescriptorForType();
       FieldDescriptor field = type.findFieldByName("value");
       if (field == null) {
-        throw new InvalidProtocolBufferException(
-            "Invalid wrapper type: " + type.getFullName());
+        throw new InvalidProtocolBufferException("Invalid wrapper type: " + type.getFullName());
       }
       builder.setField(field, parseFieldValue(field, json, builder));
     }
-    
-    private void mergeField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (field.isRepeated()) {
         if (builder.getRepeatedFieldCount(field) > 0) {
           throw new InvalidProtocolBufferException(
@@ -1273,8 +1498,11 @@
             && builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
           FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
           throw new InvalidProtocolBufferException(
-              "Cannot set field " + field.getFullName() + " because another field "
-              + other.getFullName() + " belonging to the same oneof has already been set ");
+              "Cannot set field "
+                  + field.getFullName()
+                  + " because another field "
+                  + other.getFullName()
+                  + " belonging to the same oneof has already been set ");
         }
       }
       if (field.isRepeated() && json instanceof JsonNull) {
@@ -1293,97 +1521,50 @@
         }
       }
     }
-    
-    private void mergeMapField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeMapField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect a map object but found: " + json);
+        throw new InvalidProtocolBufferException("Expect a map object but found: " + json);
       }
       Descriptor type = field.getMessageType();
       FieldDescriptor keyField = type.findFieldByName("key");
       FieldDescriptor valueField = type.findFieldByName("value");
       if (keyField == null || valueField == null) {
-        throw new InvalidProtocolBufferException(
-            "Invalid map field: " + field.getFullName());
+        throw new InvalidProtocolBufferException("Invalid map field: " + field.getFullName());
       }
       JsonObject object = (JsonObject) json;
       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
         Message.Builder entryBuilder = builder.newBuilderForField(field);
-        Object key = parseFieldValue(
-            keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
-        Object value = parseFieldValue(
-            valueField, entry.getValue(), entryBuilder);
+        Object key = parseFieldValue(keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
+        Object value = parseFieldValue(valueField, entry.getValue(), entryBuilder);
         if (value == null) {
-          throw new InvalidProtocolBufferException(
-              "Map value cannot be null.");
+          throw new InvalidProtocolBufferException("Map value cannot be null.");
         }
         entryBuilder.setField(keyField, key);
         entryBuilder.setField(valueField, value);
         builder.addRepeatedField(field, entryBuilder.build());
       }
     }
-    
-    /**
-     * Gets the default value for a field type. Note that we use proto3
-     * language defaults and ignore any default values set through the
-     * proto "default" option. 
-     */
-    private Object getDefaultValue(FieldDescriptor field,
-        Message.Builder builder) {
-      switch (field.getType()) {
-        case INT32:
-        case SINT32:
-        case SFIXED32:
-        case UINT32:
-        case FIXED32:
-          return 0;
-        case INT64:
-        case SINT64:
-        case SFIXED64:
-        case UINT64:
-        case FIXED64:
-          return 0L;
-        case FLOAT:
-          return 0.0f;
-        case DOUBLE:
-          return 0.0;
-        case BOOL:
-          return false;
-        case STRING:
-          return "";
-        case BYTES:
-          return ByteString.EMPTY;
-        case ENUM:
-          return field.getEnumType().getValues().get(0);
-        case MESSAGE:
-        case GROUP:
-          return builder.newBuilderForField(field).getDefaultInstanceForType();
-        default:
-          throw new IllegalStateException(
-              "Invalid field type: " + field.getType());
-      }
-    }
-    
-    private void mergeRepeatedField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeRepeatedField(
+        FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonArray)) {
-        throw new InvalidProtocolBufferException(
-            "Expect an array but found: " + json);
+        throw new InvalidProtocolBufferException("Expect an array but found: " + json);
       }
       JsonArray array = (JsonArray) json;
       for (int i = 0; i < array.size(); ++i) {
         Object value = parseFieldValue(field, array.get(i), builder);
         if (value == null) {
           throw new InvalidProtocolBufferException(
-              "Repeated field elements cannot be null");
+              "Repeated field elements cannot be null in field: " + field.getFullName());
         }
         builder.addRepeatedField(field, value);
       }
     }
-    
-    private int parseInt32(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private int parseInt32(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Integer.parseInt(json.getAsString());
       } catch (Exception e) {
@@ -1399,9 +1580,8 @@
         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
       }
     }
-    
-    private long parseInt64(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private long parseInt64(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Long.parseLong(json.getAsString());
       } catch (Exception e) {
@@ -1414,17 +1594,15 @@
         BigDecimal value = new BigDecimal(json.getAsString());
         return value.longValueExact();
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an int32 value: " + json);
+        throw new InvalidProtocolBufferException("Not an int64 value: " + json);
       }
     }
-    
-    private int parseUint32(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private int parseUint32(JsonElement json) throws InvalidProtocolBufferException {
       try {
         long result = Long.parseLong(json.getAsString());
         if (result < 0 || result > 0xFFFFFFFFL) {
-          throw new InvalidProtocolBufferException(
-              "Out of range uint32 value: " + json);
+          throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
         }
         return (int) result;
       } catch (InvalidProtocolBufferException e) {
@@ -1445,35 +1623,28 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an uint32 value: " + json);
+        throw new InvalidProtocolBufferException("Not an uint32 value: " + json);
       }
     }
-    
-    private static final BigInteger MAX_UINT64 =
-        new BigInteger("FFFFFFFFFFFFFFFF", 16);
-    
-    private long parseUint64(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private static final BigInteger MAX_UINT64 = new BigInteger("FFFFFFFFFFFFFFFF", 16);
+
+    private long parseUint64(JsonElement json) throws InvalidProtocolBufferException {
       try {
         BigDecimal decimalValue = new BigDecimal(json.getAsString());
         BigInteger value = decimalValue.toBigIntegerExact();
-        if (value.compareTo(BigInteger.ZERO) < 0
-            || value.compareTo(MAX_UINT64) > 0) {
-          throw new InvalidProtocolBufferException(
-              "Out of range uint64 value: " + json);
+        if (value.compareTo(BigInteger.ZERO) < 0 || value.compareTo(MAX_UINT64) > 0) {
+          throw new InvalidProtocolBufferException("Out of range uint64 value: " + json);
         }
         return value.longValue();
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an uint64 value: " + json);
+        throw new InvalidProtocolBufferException("Not an uint64 value: " + json);
       }
     }
-    
-    private boolean parseBool(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private boolean parseBool(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("true")) {
         return true;
       }
@@ -1482,11 +1653,10 @@
       }
       throw new InvalidProtocolBufferException("Invalid bool value: " + json);
     }
-    
+
     private static final double EPSILON = 1e-6;
-    
-    private float parseFloat(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private float parseFloat(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("NaN")) {
         return Float.NaN;
       } else if (json.getAsString().equals("Infinity")) {
@@ -1504,8 +1674,7 @@
         // of tolerance when checking whether the float value is in range.
         if (value > Float.MAX_VALUE * (1.0 + EPSILON)
             || value < -Float.MAX_VALUE * (1.0 + EPSILON)) {
-          throw new InvalidProtocolBufferException(
-              "Out of range float value: " + json);
+          throw new InvalidProtocolBufferException("Out of range float value: " + json);
         }
         return (float) value;
       } catch (InvalidProtocolBufferException e) {
@@ -1514,19 +1683,17 @@
         throw new InvalidProtocolBufferException("Not a float value: " + json);
       }
     }
-    
-    private static final BigDecimal MORE_THAN_ONE = new BigDecimal(
-        String.valueOf(1.0 + EPSILON));
+
+    private static final BigDecimal MORE_THAN_ONE = new BigDecimal(String.valueOf(1.0 + EPSILON));
     // When a float value is printed, the printed value might be a little
     // larger or smaller due to precision loss. Here we need to add a bit
     // of tolerance when checking whether the float value is in range.
-    private static final BigDecimal MAX_DOUBLE = new BigDecimal(
-        String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
-    private static final BigDecimal MIN_DOUBLE = new BigDecimal(
-        String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
-    
-    private double parseDouble(JsonElement json)
-        throws InvalidProtocolBufferException {
+    private static final BigDecimal MAX_DOUBLE =
+        new BigDecimal(String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+    private static final BigDecimal MIN_DOUBLE =
+        new BigDecimal(String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+
+    private double parseDouble(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("NaN")) {
         return Double.NaN;
       } else if (json.getAsString().equals("Infinity")) {
@@ -1539,36 +1706,31 @@
         // accepts all values. Here we parse the value into a BigDecimal and do
         // explicit range check on it.
         BigDecimal value = new BigDecimal(json.getAsString());
-        if (value.compareTo(MAX_DOUBLE) > 0
-            || value.compareTo(MIN_DOUBLE) < 0) {
-          throw new InvalidProtocolBufferException(
-              "Out of range double value: " + json);
+        if (value.compareTo(MAX_DOUBLE) > 0 || value.compareTo(MIN_DOUBLE) < 0) {
+          throw new InvalidProtocolBufferException("Out of range double value: " + json);
         }
         return value.doubleValue();
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an double value: " + json);
+        throw new InvalidProtocolBufferException("Not an double value: " + json);
       }
     }
-    
+
     private String parseString(JsonElement json) {
       return json.getAsString();
     }
-    
+
     private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
-      String encoded = json.getAsString();
-      if (encoded.length() % 4 != 0) {
-        throw new InvalidProtocolBufferException(
-            "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
+      try {
+        return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
+      } catch (IllegalArgumentException e) {
+        return ByteString.copyFrom(BaseEncoding.base64Url().decode(json.getAsString()));
       }
-      return ByteString.copyFrom(
-          BaseEncoding.base64().decode(json.getAsString()));
     }
-    
-    private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor,
-        JsonElement json) throws InvalidProtocolBufferException {
+
+    private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json)
+        throws InvalidProtocolBufferException {
       String value = json.getAsString();
       EnumValueDescriptor result = enumDescriptor.findValueByName(value);
       if (result == null) {
@@ -1585,27 +1747,28 @@
           // that's not the exception we want the user to see. Since result == null, we will throw
           // an exception later.
         }
-        
+
         if (result == null) {
           throw new InvalidProtocolBufferException(
-              "Invalid enum value: " + value + " for enum type: "
-              + enumDescriptor.getFullName());
+              "Invalid enum value: " + value + " for enum type: " + enumDescriptor.getFullName());
         }
       }
       return result;
     }
-    
-    private Object parseFieldValue(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (json instanceof JsonNull) {
         if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
-            && field.getMessageType().getFullName().equals(
-                   Value.getDescriptor().getFullName())) {
+            && field.getMessageType().getFullName().equals(Value.getDescriptor().getFullName())) {
           // For every other type, "null" means absence, but for the special
           // Value message, it means the "null_value" field has been set.
           Value value = Value.newBuilder().setNullValueValue(0).build();
-          return builder.newBuilderForField(field).mergeFrom(
-              value.toByteString()).build();
+          return builder.newBuilderForField(field).mergeFrom(value.toByteString()).build();
+        } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM
+            && field.getEnumType().getFullName().equals(NullValue.getDescriptor().getFullName())) {
+          // If the type of the field is a NullValue, then the value should be explicitly set.
+          return field.getEnumType().findValueByNumber(0);
         }
         return null;
       }
@@ -1625,7 +1788,7 @@
 
         case FLOAT:
           return parseFloat(json);
-          
+
         case DOUBLE:
           return parseDouble(json);
 
@@ -1648,14 +1811,18 @@
 
         case MESSAGE:
         case GROUP:
+          if (currentDepth >= recursionLimit) {
+            throw new InvalidProtocolBufferException("Hit recursion limit.");
+          }
+          ++currentDepth;
           Message.Builder subBuilder = builder.newBuilderForField(field);
           merge(json, subBuilder);
+          --currentDepth;
           return subBuilder.build();
-          
+
         default:
-          throw new InvalidProtocolBufferException(
-              "Invalid field type: " + field.getType());
-      } 
+          throw new InvalidProtocolBufferException("Invalid field type: " + field.getType());
+      }
     }
   }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
index 3033182..0475847 100644
--- a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -35,15 +35,14 @@
 
 import java.math.BigInteger;
 import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
 
 /**
  * Utilities to help create/manipulate Timestamp/Duration
+ *
+ * @deprecated Use {@link Durations} and {@link Timestamps} instead.
  */
-public class TimeUtil {
+@Deprecated
+public final class TimeUtil {
   // Timestamp for "0001-01-01T00:00:00Z"
   public static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
 
@@ -53,28 +52,6 @@
   public static final long DURATION_SECONDS_MAX = 315576000000L;
 
   private static final long NANOS_PER_SECOND = 1000000000;
-  private static final long NANOS_PER_MILLISECOND = 1000000;
-  private static final long NANOS_PER_MICROSECOND = 1000;
-  private static final long MILLIS_PER_SECOND = 1000;
-  private static final long MICROS_PER_SECOND = 1000000;
-
-  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
-      new ThreadLocal<SimpleDateFormat>() {
-        protected SimpleDateFormat initialValue() {
-          return createTimestampFormat();
-        }
-      };
-
-  private static SimpleDateFormat createTimestampFormat() {
-    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
-    GregorianCalendar calendar =
-      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
-    // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
-    // backwards to year one) for timestamp formating.
-    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
-    sdf.setCalendar(calendar);
-    return sdf;
-  }
 
   private TimeUtil() {}
 
@@ -90,27 +67,11 @@
    * @return The string representation of the given timestamp.
    * @throws IllegalArgumentException if the given timestamp is not in the
    *         valid range.
+   * @deprecated Use {@link Timestamps#toString} instead.
    */
-  public static String toString(Timestamp timestamp)
-    throws IllegalArgumentException {
-    StringBuilder result = new StringBuilder();
-    // Format the seconds part.
-    if (timestamp.getSeconds() < TIMESTAMP_SECONDS_MIN
-        || timestamp.getSeconds() > TIMESTAMP_SECONDS_MAX) {
-      throw new IllegalArgumentException("Timestamp is out of range.");
-    }
-    Date date = new Date(timestamp.getSeconds() * MILLIS_PER_SECOND);
-    result.append(timestampFormat.get().format(date));
-    // Format the nanos part.
-    if (timestamp.getNanos() < 0 || timestamp.getNanos() >= NANOS_PER_SECOND) {
-      throw new IllegalArgumentException("Timestamp has invalid nanos value.");
-    }
-    if (timestamp.getNanos() != 0) {
-      result.append(".");
-      result.append(formatNanos(timestamp.getNanos()));
-    }
-    result.append("Z");
-    return result.toString();
+  @Deprecated
+  public static String toString(Timestamp timestamp) {
+    return Timestamps.toString(timestamp);
   }
 
   /**
@@ -123,59 +84,11 @@
    *
    * @return A Timestamp parsed from the string.
    * @throws ParseException if parsing fails.
+   * @deprecated Use {@link Timestamps#parse} instead.
    */
-
+  @Deprecated
   public static Timestamp parseTimestamp(String value) throws ParseException {
-    int dayOffset = value.indexOf('T');
-    if (dayOffset == -1) {
-      throw new ParseException(
-        "Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
-    }
-    int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
-    if (timezoneOffsetPosition == -1) {
-      timezoneOffsetPosition = value.indexOf('+', dayOffset);
-    }
-    if (timezoneOffsetPosition == -1) {
-      timezoneOffsetPosition = value.indexOf('-', dayOffset);
-    }
-    if (timezoneOffsetPosition == -1) {
-      throw new ParseException(
-        "Failed to parse timestamp: missing valid timezone offset.", 0);
-    }
-    // Parse seconds and nanos.
-    String timeValue = value.substring(0, timezoneOffsetPosition);
-    String secondValue = timeValue;
-    String nanoValue = "";
-    int pointPosition = timeValue.indexOf('.');
-    if (pointPosition != -1) {
-      secondValue = timeValue.substring(0, pointPosition);
-      nanoValue = timeValue.substring(pointPosition + 1);
-    }
-    Date date = timestampFormat.get().parse(secondValue);
-    long seconds = date.getTime() / MILLIS_PER_SECOND;
-    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
-    // Parse timezone offsets.
-    if (value.charAt(timezoneOffsetPosition) == 'Z') {
-      if (value.length() != timezoneOffsetPosition + 1) {
-        throw new ParseException(
-          "Failed to parse timestamp: invalid trailing data \""
-          + value.substring(timezoneOffsetPosition) + "\"", 0);
-      }
-    } else {
-      String offsetValue = value.substring(timezoneOffsetPosition + 1);
-      long offset = parseTimezoneOffset(offsetValue);
-      if (value.charAt(timezoneOffsetPosition) == '+') {
-        seconds -= offset;
-      } else {
-        seconds += offset;
-      }
-    }
-    try {
-      return normalizedTimestamp(seconds, nanos);
-    } catch (IllegalArgumentException e) {
-      throw new ParseException(
-        "Failed to parse timestmap: timestamp is out of range.", 0);
-    }
+    return Timestamps.parse(value);
   }
 
   /**
@@ -188,33 +101,11 @@
    * @return The string representation of the given duration.
    * @throws IllegalArgumentException if the given duration is not in the valid
    *         range.
+   * @deprecated Use {@link Durations#toString} instead.
    */
-  public static String toString(Duration duration)
-    throws IllegalArgumentException {
-    if (duration.getSeconds() < DURATION_SECONDS_MIN
-      || duration.getSeconds() > DURATION_SECONDS_MAX) {
-      throw new IllegalArgumentException("Duration is out of valid range.");
-    }
-    StringBuilder result = new StringBuilder();
-    long seconds = duration.getSeconds();
-    int nanos = duration.getNanos();
-    if (seconds < 0 || nanos < 0) {
-      if (seconds > 0 || nanos > 0) {
-        throw new IllegalArgumentException(
-            "Invalid duration: seconds value and nanos value must have the same"
-            + "sign.");
-      }
-      result.append("-");
-      seconds = -seconds;
-      nanos = -nanos;
-    }
-    result.append(seconds);
-    if (nanos != 0) {
-      result.append(".");
-      result.append(formatNanos(nanos));
-    }
-    result.append("s");
-    return result.toString();
+  @Deprecated
+  public static String toString(Duration duration) {
+    return Durations.toString(duration);
   }
 
   /**
@@ -222,54 +113,31 @@
    *
    * @return A Duration parsed from the string.
    * @throws ParseException if parsing fails.
+   * @deprecated Use {@link Durations#parse} instead.
    */
+  @Deprecated
   public static Duration parseDuration(String value) throws ParseException {
-    // Must ended with "s".
-    if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
-      throw new ParseException("Invalid duration string: " + value, 0);
-    }
-    boolean negative = false;
-    if (value.charAt(0) == '-') {
-      negative = true;
-      value = value.substring(1);
-    }
-    String secondValue = value.substring(0, value.length() - 1);
-    String nanoValue = "";
-    int pointPosition = secondValue.indexOf('.');
-    if (pointPosition != -1) {
-      nanoValue = secondValue.substring(pointPosition + 1);
-      secondValue = secondValue.substring(0, pointPosition);
-    }
-    long seconds = Long.parseLong(secondValue);
-    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
-    if (seconds < 0) {
-      throw new ParseException("Invalid duration string: " + value, 0);
-    }
-    if (negative) {
-      seconds = -seconds;
-      nanos = -nanos;
-    }
-    try {
-      return normalizedDuration(seconds, nanos);
-    } catch (IllegalArgumentException e) {
-      throw new ParseException("Duration value is out of range.", 0);
-    }
+    return Durations.parse(value);
   }
 
   /**
    * Create a Timestamp from the number of milliseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromMillis} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromMillis(long milliseconds) {
-    return normalizedTimestamp(milliseconds / MILLIS_PER_SECOND,
-      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+    return Timestamps.fromMillis(milliseconds);
   }
 
   /**
    * Create a Duration from the number of milliseconds.
+   *
+   * @deprecated Use {@link Durations#fromMillis} instead.
    */
+  @Deprecated
   public static Duration createDurationFromMillis(long milliseconds) {
-    return normalizedDuration(milliseconds / MILLIS_PER_SECOND,
-      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+    return Durations.fromMillis(milliseconds);
   }
 
   /**
@@ -278,36 +146,44 @@
    * <p>The result will be rounded down to the nearest millisecond. E.g., if the
    * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
    * to -1 millisecond.
+   *
+   * @deprecated Use {@link Timestamps#toMillis} instead.
    */
+  @Deprecated
   public static long toMillis(Timestamp timestamp) {
-    return timestamp.getSeconds() * MILLIS_PER_SECOND + timestamp.getNanos()
-      / NANOS_PER_MILLISECOND;
+    return Timestamps.toMillis(timestamp);
   }
 
   /**
    * Convert a Duration to the number of milliseconds.The result will be
    * rounded towards 0 to the nearest millisecond. E.g., if the duration
    * represents -1 nanosecond, it will be rounded to 0.
+   *
+   * @deprecated Use {@link Durations#toMillis} instead.
    */
+  @Deprecated
   public static long toMillis(Duration duration) {
-    return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos()
-      / NANOS_PER_MILLISECOND;
+    return Durations.toMillis(duration);
   }
 
   /**
    * Create a Timestamp from the number of microseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromMicros} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromMicros(long microseconds) {
-    return normalizedTimestamp(microseconds / MICROS_PER_SECOND,
-      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+    return Timestamps.fromMicros(microseconds);
   }
 
   /**
    * Create a Duration from the number of microseconds.
+   *
+   * @deprecated Use {@link Durations#fromMicros} instead.
    */
+  @Deprecated
   public static Duration createDurationFromMicros(long microseconds) {
-    return normalizedDuration(microseconds / MICROS_PER_SECOND,
-      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+    return Durations.fromMicros(microseconds);
   }
 
   /**
@@ -316,111 +192,141 @@
    * <p>The result will be rounded down to the nearest microsecond. E.g., if the
    * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
    * to -1 millisecond.
+   *
+   * @deprecated Use {@link Timestamps#toMicros} instead.
    */
+  @Deprecated
   public static long toMicros(Timestamp timestamp) {
-    return timestamp.getSeconds() * MICROS_PER_SECOND + timestamp.getNanos()
-      / NANOS_PER_MICROSECOND;
+    return Timestamps.toMicros(timestamp);
   }
 
   /**
    * Convert a Duration to the number of microseconds.The result will be
    * rounded towards 0 to the nearest microseconds. E.g., if the duration
    * represents -1 nanosecond, it will be rounded to 0.
+   *
+   * @deprecated Use {@link Durations#toMicros} instead.
    */
+  @Deprecated
   public static long toMicros(Duration duration) {
-    return duration.getSeconds() * MICROS_PER_SECOND + duration.getNanos()
-      / NANOS_PER_MICROSECOND;
+    return Durations.toMicros(duration);
   }
 
   /**
    * Create a Timestamp from the number of nanoseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromNanos} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromNanos(long nanoseconds) {
-    return normalizedTimestamp(nanoseconds / NANOS_PER_SECOND,
-      (int) (nanoseconds % NANOS_PER_SECOND));
+    return Timestamps.fromNanos(nanoseconds);
   }
 
   /**
    * Create a Duration from the number of nanoseconds.
+   *
+   * @deprecated Use {@link Durations#fromNanos} instead.
    */
+  @Deprecated
   public static Duration createDurationFromNanos(long nanoseconds) {
-    return normalizedDuration(nanoseconds / NANOS_PER_SECOND,
-      (int) (nanoseconds % NANOS_PER_SECOND));
+    return Durations.fromNanos(nanoseconds);
   }
 
   /**
    * Convert a Timestamp to the number of nanoseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#toNanos} instead.
    */
+  @Deprecated
   public static long toNanos(Timestamp timestamp) {
-    return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
+    return Timestamps.toNanos(timestamp);
   }
 
   /**
    * Convert a Duration to the number of nanoseconds.
+   *
+   * @deprecated Use {@link Durations#toNanos} instead.
    */
+  @Deprecated
   public static long toNanos(Duration duration) {
-    return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
+    return Durations.toNanos(duration);
   }
 
   /**
    * Get the current time.
+   *
+   * @deprecated Use {@code Timestamps.fromMillis(System.currentTimeMillis())} instead.
    */
+  @Deprecated
   public static Timestamp getCurrentTime() {
-    return createTimestampFromMillis(System.currentTimeMillis());
+    return Timestamps.fromMillis(System.currentTimeMillis());
   }
 
   /**
    * Get the epoch.
+   *
+   * @deprecated Use {@code Timestamps.fromMillis(0)} instead.
    */
+  @Deprecated
   public static Timestamp getEpoch() {
     return Timestamp.getDefaultInstance();
   }
 
   /**
    * Calculate the difference between two timestamps.
+   *
+   * @deprecated Use {@link Timestamps#between} instead.
    */
+  @Deprecated
   public static Duration distance(Timestamp from, Timestamp to) {
-    return normalizedDuration(to.getSeconds() - from.getSeconds(),
-      to.getNanos() - from.getNanos());
+    return Timestamps.between(from, to);
   }
 
   /**
    * Add a duration to a timestamp.
+   *
+   * @deprecated Use {@link Timestamps#add} instead.
    */
+  @Deprecated
   public static Timestamp add(Timestamp start, Duration length) {
-    return normalizedTimestamp(start.getSeconds() + length.getSeconds(),
-      start.getNanos() + length.getNanos());
+    return Timestamps.add(start, length);
   }
 
   /**
    * Subtract a duration from a timestamp.
+   *
+   * @deprecated Use {@link Timestamps#subtract} instead.
    */
+  @Deprecated
   public static Timestamp subtract(Timestamp start, Duration length) {
-    return normalizedTimestamp(start.getSeconds() - length.getSeconds(),
-      start.getNanos() - length.getNanos());
+    return Timestamps.subtract(start, length);
   }
 
   /**
    * Add two durations.
+   *
+   * @deprecated Use {@link Durations#add} instead.
    */
+  @Deprecated
   public static Duration add(Duration d1, Duration d2) {
-    return normalizedDuration(d1.getSeconds() + d2.getSeconds(),
-      d1.getNanos() + d2.getNanos());
+    return Durations.add(d1, d2);
   }
 
   /**
    * Subtract a duration from another.
+   *
+   * @deprecated Use {@link Durations#subtract} instead.
    */
+  @Deprecated
   public static Duration subtract(Duration d1, Duration d2) {
-    return normalizedDuration(d1.getSeconds() - d2.getSeconds(),
-      d1.getNanos() - d2.getNanos());
+    return Durations.subtract(d1, d2);
   }
 
   // Multiplications and divisions.
 
+  // TODO(kak): Delete this.
   public static Duration multiply(Duration duration, double times) {
-    double result = duration.getSeconds() * times + duration.getNanos() * times
-      / 1000000000.0;
+    double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0;
     if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {
       throw new IllegalArgumentException("Result is out of valid range.");
     }
@@ -428,50 +334,49 @@
     int nanos = (int) ((result - seconds) * 1000000000);
     return normalizedDuration(seconds, nanos);
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration divide(Duration duration, double value) {
     return multiply(duration, 1.0 / value);
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration multiply(Duration duration, long times) {
-    return createDurationFromBigInteger(
-      toBigInteger(duration).multiply(toBigInteger(times)));
+    return createDurationFromBigInteger(toBigInteger(duration).multiply(toBigInteger(times)));
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration divide(Duration duration, long times) {
-    return createDurationFromBigInteger(
-      toBigInteger(duration).divide(toBigInteger(times)));
+    return createDurationFromBigInteger(toBigInteger(duration).divide(toBigInteger(times)));
   }
-  
+
+  // TODO(kak): Delete this.
   public static long divide(Duration d1, Duration d2) {
     return toBigInteger(d1).divide(toBigInteger(d2)).longValue();
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration remainder(Duration d1, Duration d2) {
-    return createDurationFromBigInteger(
-      toBigInteger(d1).remainder(toBigInteger(d2)));
+    return createDurationFromBigInteger(toBigInteger(d1).remainder(toBigInteger(d2)));
   }
-  
+
   private static final BigInteger NANOS_PER_SECOND_BIG_INTEGER =
       new BigInteger(String.valueOf(NANOS_PER_SECOND));
-  
+
   private static BigInteger toBigInteger(Duration duration) {
     return toBigInteger(duration.getSeconds())
-      .multiply(NANOS_PER_SECOND_BIG_INTEGER)
-      .add(toBigInteger(duration.getNanos()));
+        .multiply(NANOS_PER_SECOND_BIG_INTEGER)
+        .add(toBigInteger(duration.getNanos()));
   }
-  
+
   private static BigInteger toBigInteger(long value) {
     return new BigInteger(String.valueOf(value));
   }
-  
+
   private static Duration createDurationFromBigInteger(BigInteger value) {
-    long seconds = value.divide(
-      new BigInteger(String.valueOf(NANOS_PER_SECOND))).longValue();
-    int nanos = value.remainder(
-      new BigInteger(String.valueOf(NANOS_PER_SECOND))).intValue();
+    long seconds = value.divide(new BigInteger(String.valueOf(NANOS_PER_SECOND))).longValue();
+    int nanos = value.remainder(new BigInteger(String.valueOf(NANOS_PER_SECOND))).intValue();
     return normalizedDuration(seconds, nanos);
-    
   }
 
   private static Duration normalizedDuration(long seconds, int nanos) {
@@ -492,58 +397,4 @@
     }
     return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
   }
-
-  private static Timestamp normalizedTimestamp(long seconds, int nanos) {
-    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
-      seconds += nanos / NANOS_PER_SECOND;
-      nanos %= NANOS_PER_SECOND;
-    }
-    if (nanos < 0) {
-      nanos += NANOS_PER_SECOND;
-      seconds -= 1;
-    }
-    if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
-      throw new IllegalArgumentException("Timestamp is out of valid range.");
-    }
-    return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
-  }
-
-  /**
-   * Format the nano part of a timestamp or a duration.
-   */
-  private static String formatNanos(int nanos) {
-    assert nanos >= 1 && nanos <= 999999999;
-    // Determine whether to use 3, 6, or 9 digits for the nano part.
-    if (nanos % NANOS_PER_MILLISECOND == 0) {
-      return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);
-    } else if (nanos % NANOS_PER_MICROSECOND == 0) {
-      return String.format("%1$06d", nanos / NANOS_PER_MICROSECOND);
-    } else {
-      return String.format("%1$09d", nanos);
-    }
-  }
-
-  private static int parseNanos(String value) throws ParseException {
-    int result = 0;
-    for (int i = 0; i < 9; ++i) {
-      result = result * 10;
-      if (i < value.length()) {
-        if (value.charAt(i) < '0' || value.charAt(i) > '9') {
-          throw new ParseException("Invalid nanosecnds.", 0);
-        }
-        result += value.charAt(i) - '0';
-      }
-    }
-    return result;
-  }
-
-  private static long parseTimezoneOffset(String value) throws ParseException {
-    int pos = value.indexOf(':');
-    if (pos == -1) {
-      throw new ParseException("Invalid offset value: " + value, 0);
-    }
-    String hours = value.substring(0, pos);
-    String minutes = value.substring(pos + 1);
-    return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
-  }
 }
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
new file mode 100644
index 0000000..9e528d4
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -0,0 +1,413 @@
+// 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.util;
+
+import static com.google.common.math.IntMath.checkedAdd;
+import static com.google.common.math.IntMath.checkedSubtract;
+import static com.google.common.math.LongMath.checkedAdd;
+import static com.google.common.math.LongMath.checkedMultiply;
+import static com.google.common.math.LongMath.checkedSubtract;
+
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Utilities to help create/manipulate {@code protobuf/timestamp.proto}. All operations throw an
+ * {@link IllegalArgumentException} if the input(s) are not {@linkplain #isValid(Timestamp) valid}.
+ */
+public final class Timestamps {
+
+  // Timestamp for "0001-01-01T00:00:00Z"
+  static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
+
+  // Timestamp for "9999-12-31T23:59:59Z"
+  static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
+
+  static final long NANOS_PER_SECOND = 1000000000;
+  static final long NANOS_PER_MILLISECOND = 1000000;
+  static final long NANOS_PER_MICROSECOND = 1000;
+  static final long MILLIS_PER_SECOND = 1000;
+  static final long MICROS_PER_SECOND = 1000000;
+
+  /** A constant holding the minimum valid {@link Timestamp}, {@code 0001-01-01T00:00:00Z}. */
+  public static final Timestamp MIN_VALUE =
+      Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MIN).setNanos(0).build();
+
+  /**
+   * A constant holding the maximum valid {@link Timestamp}, {@code 9999-12-31T23:59:59.999999999Z}.
+   */
+  public static final Timestamp MAX_VALUE =
+      Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MAX).setNanos(999999999).build();
+
+  /**
+   * A constant holding the {@link Timestamp} of epoch time, {@code 1970-01-01T00:00:00.000000000Z}.
+   */
+  public static final Timestamp EPOCH = Timestamp.newBuilder().setSeconds(0).setNanos(0).build();
+
+  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
+      new ThreadLocal<SimpleDateFormat>() {
+        @Override
+        protected SimpleDateFormat initialValue() {
+          return createTimestampFormat();
+        }
+      };
+
+  private static SimpleDateFormat createTimestampFormat() {
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
+    GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
+    // backwards to year one) for timestamp formating.
+    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
+    sdf.setCalendar(calendar);
+    return sdf;
+  }
+
+  private Timestamps() {}
+
+  private static final Comparator<Timestamp> COMPARATOR =
+      new Comparator<Timestamp>() {
+        @Override
+        public int compare(Timestamp t1, Timestamp t2) {
+          checkValid(t1);
+          checkValid(t2);
+          int secDiff = Long.compare(t1.getSeconds(), t2.getSeconds());
+          return (secDiff != 0) ? secDiff : Integer.compare(t1.getNanos(), t2.getNanos());
+        }
+      };
+
+  /**
+   * Returns a {@link Comparator} for {@link Timestamp}s which sorts in increasing chronological
+   * order. Nulls and invalid {@link Timestamp}s are not allowed (see {@link #isValid}).
+   */
+  public static Comparator<Timestamp> comparator() {
+    return COMPARATOR;
+  }
+
+  /**
+   * Compares two timestamps. The value returned is identical to what would be returned by:
+   * {@code Timestamps.comparator().compare(x, y)}.
+   *
+   * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
+   *     and a value greater than {@code 0} if {@code x > y}
+   */
+  public static int compare(Timestamp x, Timestamp y) {
+    return COMPARATOR.compare(x, y);
+  }
+
+  /**
+   * Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the
+   * range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and
+   * 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range [0, +999,999,999].
+   *
+   * <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
+   * nanos values that count forward in time.
+   */
+  public static boolean isValid(Timestamp timestamp) {
+    return isValid(timestamp.getSeconds(), timestamp.getNanos());
+  }
+
+  /**
+   * Returns true if the given number of seconds and nanos is a valid {@link Timestamp}. The {@code
+   * seconds} value must be in the range [-62,135,596,800, +253,402,300,799] (i.e., between
+   * 0001-01-01T00:00:00Z and 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range
+   * [0, +999,999,999].
+   *
+   * <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
+   * nanos values that count forward in time.
+   */
+  public static boolean isValid(long seconds, int nanos) {
+    if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
+      return false;
+    }
+    if (nanos < 0 || nanos >= NANOS_PER_SECOND) {
+      return false;
+    }
+    return true;
+  }
+
+  /** Throws an {@link IllegalArgumentException} if the given {@link Timestamp} is not valid. */
+  public static Timestamp checkValid(Timestamp timestamp) {
+    long seconds = timestamp.getSeconds();
+    int nanos = timestamp.getNanos();
+    if (!isValid(seconds, nanos)) {
+        throw new IllegalArgumentException(String.format(
+            "Timestamp is not valid. See proto definition for valid values. "
+            + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
+            + "Nanos (%s) must be in range [0, +999,999,999].", seconds, nanos));
+    }
+    return timestamp;
+  }
+
+  /**
+   * Convert Timestamp to RFC 3339 date string format. The output will always be Z-normalized and
+   * uses 3, 6 or 9 fractional digits as required to represent the exact value. Note that Timestamp
+   * can only represent time from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. See
+   * https://www.ietf.org/rfc/rfc3339.txt
+   *
+   * <p>Example of generated format: "1972-01-01T10:00:20.021Z"
+   *
+   * @return The string representation of the given timestamp.
+   * @throws IllegalArgumentException if the given timestamp is not in the valid range.
+   */
+  public static String toString(Timestamp timestamp) {
+    checkValid(timestamp);
+
+    long seconds = timestamp.getSeconds();
+    int nanos = timestamp.getNanos();
+
+    StringBuilder result = new StringBuilder();
+    // Format the seconds part.
+    Date date = new Date(seconds * MILLIS_PER_SECOND);
+    result.append(timestampFormat.get().format(date));
+    // Format the nanos part.
+    if (nanos != 0) {
+      result.append(".");
+      result.append(formatNanos(nanos));
+    }
+    result.append("Z");
+    return result.toString();
+  }
+
+  /**
+   * Parse from RFC 3339 date string to Timestamp. This method accepts all outputs of {@link
+   * #toString(Timestamp)} and it also accepts any fractional digits (or none) and any offset as
+   * long as they fit into nano-seconds precision.
+   *
+   * <p>Example of accepted format: "1972-01-01T10:00:20.021-05:00"
+   *
+   * @return A Timestamp parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+  public static Timestamp parse(String value) throws ParseException {
+    int dayOffset = value.indexOf('T');
+    if (dayOffset == -1) {
+      throw new ParseException("Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
+    }
+    int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('+', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('-', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      throw new ParseException("Failed to parse timestamp: missing valid timezone offset.", 0);
+    }
+    // Parse seconds and nanos.
+    String timeValue = value.substring(0, timezoneOffsetPosition);
+    String secondValue = timeValue;
+    String nanoValue = "";
+    int pointPosition = timeValue.indexOf('.');
+    if (pointPosition != -1) {
+      secondValue = timeValue.substring(0, pointPosition);
+      nanoValue = timeValue.substring(pointPosition + 1);
+    }
+    Date date = timestampFormat.get().parse(secondValue);
+    long seconds = date.getTime() / MILLIS_PER_SECOND;
+    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
+    // Parse timezone offsets.
+    if (value.charAt(timezoneOffsetPosition) == 'Z') {
+      if (value.length() != timezoneOffsetPosition + 1) {
+        throw new ParseException(
+            "Failed to parse timestamp: invalid trailing data \""
+                + value.substring(timezoneOffsetPosition)
+                + "\"",
+            0);
+      }
+    } else {
+      String offsetValue = value.substring(timezoneOffsetPosition + 1);
+      long offset = parseTimezoneOffset(offsetValue);
+      if (value.charAt(timezoneOffsetPosition) == '+') {
+        seconds -= offset;
+      } else {
+        seconds += offset;
+      }
+    }
+    try {
+      return normalizedTimestamp(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException("Failed to parse timestamp: timestamp is out of range.", 0);
+    }
+  }
+
+  /** Create a Timestamp from the number of seconds elapsed from the epoch. */
+  public static Timestamp fromSeconds(long seconds) {
+    return normalizedTimestamp(seconds, 0);
+  }
+
+  /**
+   * Convert a Timestamp to the number of seconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents
+   * "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second.
+   */
+  public static long toSeconds(Timestamp timestamp) {
+    return checkValid(timestamp).getSeconds();
+  }
+
+  /** Create a Timestamp from the number of milliseconds elapsed from the epoch. */
+  public static Timestamp fromMillis(long milliseconds) {
+    return normalizedTimestamp(
+        milliseconds / MILLIS_PER_SECOND,
+        (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of milliseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
+   * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
+   */
+  public static long toMillis(Timestamp timestamp) {
+    checkValid(timestamp);
+    return checkedAdd(
+        checkedMultiply(timestamp.getSeconds(), MILLIS_PER_SECOND),
+        timestamp.getNanos() / NANOS_PER_MILLISECOND);
+  }
+
+  /** Create a Timestamp from the number of microseconds elapsed from the epoch. */
+  public static Timestamp fromMicros(long microseconds) {
+    return normalizedTimestamp(
+        microseconds / MICROS_PER_SECOND,
+        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of microseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
+   * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond.
+   */
+  public static long toMicros(Timestamp timestamp) {
+    checkValid(timestamp);
+    return checkedAdd(
+        checkedMultiply(timestamp.getSeconds(), MICROS_PER_SECOND),
+        timestamp.getNanos() / NANOS_PER_MICROSECOND);
+  }
+
+  /** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */
+  public static Timestamp fromNanos(long nanoseconds) {
+    return normalizedTimestamp(
+        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */
+  public static long toNanos(Timestamp timestamp) {
+    checkValid(timestamp);
+    return checkedAdd(
+        checkedMultiply(timestamp.getSeconds(), NANOS_PER_SECOND), timestamp.getNanos());
+  }
+
+  /** Calculate the difference between two timestamps. */
+  public static Duration between(Timestamp from, Timestamp to) {
+    checkValid(from);
+    checkValid(to);
+    return Durations.normalizedDuration(
+        checkedSubtract(to.getSeconds(), from.getSeconds()),
+        checkedSubtract(to.getNanos(), from.getNanos()));
+  }
+
+  /** Add a duration to a timestamp. */
+  public static Timestamp add(Timestamp start, Duration length) {
+    checkValid(start);
+    Durations.checkValid(length);
+    return normalizedTimestamp(
+        checkedAdd(start.getSeconds(), length.getSeconds()),
+        checkedAdd(start.getNanos(), length.getNanos()));
+  }
+
+  /** Subtract a duration from a timestamp. */
+  public static Timestamp subtract(Timestamp start, Duration length) {
+    checkValid(start);
+    Durations.checkValid(length);
+    return normalizedTimestamp(
+        checkedSubtract(start.getSeconds(), length.getSeconds()),
+        checkedSubtract(start.getNanos(), length.getNanos()));
+  }
+
+  static Timestamp normalizedTimestamp(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
+      nanos = (int) (nanos % NANOS_PER_SECOND);
+    }
+    if (nanos < 0) {
+      nanos =
+          (int)
+              (nanos + NANOS_PER_SECOND); // no overflow since nanos is negative (and we're adding)
+      seconds = checkedSubtract(seconds, 1);
+    }
+    Timestamp timestamp = Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+    return checkValid(timestamp);
+  }
+
+  private static long parseTimezoneOffset(String value) throws ParseException {
+    int pos = value.indexOf(':');
+    if (pos == -1) {
+      throw new ParseException("Invalid offset value: " + value, 0);
+    }
+    String hours = value.substring(0, pos);
+    String minutes = value.substring(pos + 1);
+    return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
+  }
+
+  static int parseNanos(String value) throws ParseException {
+    int result = 0;
+    for (int i = 0; i < 9; ++i) {
+      result = result * 10;
+      if (i < value.length()) {
+        if (value.charAt(i) < '0' || value.charAt(i) > '9') {
+          throw new ParseException("Invalid nanoseconds.", 0);
+        }
+        result += value.charAt(i) - '0';
+      }
+    }
+    return result;
+  }
+
+  /** Format the nano part of a timestamp or a duration. */
+  static String formatNanos(int nanos) {
+    // Determine whether to use 3, 6, or 9 digits for the nano part.
+    if (nanos % NANOS_PER_MILLISECOND == 0) {
+      return String.format(Locale.ENGLISH, "%1$03d", nanos / NANOS_PER_MILLISECOND);
+    } else if (nanos % NANOS_PER_MICROSECOND == 0) {
+      return String.format(Locale.ENGLISH, "%1$06d", nanos / NANOS_PER_MICROSECOND);
+    } else {
+      return String.format(Locale.ENGLISH, "%1$09d", nanos);
+    }
+  }
+}
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 3391f23..853b615 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
@@ -33,7 +33,6 @@
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
-
 import junit.framework.TestCase;
 
 public class FieldMaskTreeTest extends TestCase {
@@ -61,19 +60,16 @@
     tree.addFieldPath("bar");
     assertEquals("bar,foo", tree.toString());
   }
-  
+
   public void testMergeFromFieldMask() throws Exception {
-    FieldMaskTree tree = new FieldMaskTree(
-      FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+    FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
     assertEquals("bar.baz,bar.quz,foo", tree.toString());
-    tree.mergeFromFieldMask(
-      FieldMaskUtil.fromString("foo.bar,bar"));
+    tree.mergeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar"));
     assertEquals("bar,foo", tree.toString());
   }
-  
+
   public void testIntersectFieldPath() throws Exception {
-    FieldMaskTree tree = new FieldMaskTree(
-      FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+    FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
     FieldMaskTree result = new FieldMaskTree();
     // Empty path.
     tree.intersectFieldPath("", result);
@@ -96,16 +92,18 @@
   }
 
   public void testMerge() throws Exception {
-    TestAllTypes value = TestAllTypes.newBuilder()
-        .setOptionalInt32(1234)
-        .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678))
-        .addRepeatedInt32(4321)
-        .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765))
-        .build();
-    NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
-        .setPayload(value)
-        .setChild(NestedTestAllTypes.newBuilder().setPayload(value))
-        .build();
+    TestAllTypes value =
+        TestAllTypes.newBuilder()
+            .setOptionalInt32(1234)
+            .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678))
+            .addRepeatedInt32(4321)
+            .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765))
+            .build();
+    NestedTestAllTypes source =
+        NestedTestAllTypes.newBuilder()
+            .setPayload(value)
+            .setChild(NestedTestAllTypes.newBuilder().setPayload(value))
+            .build();
     // Now we have a message source with the following structure:
     //   [root] -+- payload -+- optional_int32
     //           |           +- optional_nested_message
@@ -116,114 +114,154 @@
     //                                 +- optional_nested_message
     //                                 +- repeated_int32
     //                                 +- repeated_nested_message
-    
+
     FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions();
-    
+
     // Test merging each individual field.
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.optional_int32")
-        .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options);
     NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().setOptionalInt32(1234);
     assertEquals(expected.build(), builder.build());
 
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.optional_nested_message")
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_nested_message")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
-    expected.getPayloadBuilder().setOptionalNestedMessage(
-        NestedMessage.newBuilder().setBb(5678));
+    expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
     assertEquals(expected.build(), builder.build());
 
-
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.repeated_int32")
-        .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedInt32(4321);
     assertEquals(expected.build(), builder.build());
 
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.repeated_nested_message")
+    new FieldMaskTree()
+        .addFieldPath("payload.repeated_nested_message")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
-    expected.getPayloadBuilder().addRepeatedNestedMessage(
-        NestedMessage.newBuilder().setBb(8765));
+    expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
     assertEquals(expected.build(), builder.build());
 
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("child.payload.optional_int32")
+    new FieldMaskTree()
+        .addFieldPath("child.payload.optional_int32")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
     assertEquals(expected.build(), builder.build());
 
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("child.payload.optional_nested_message")
+    new FieldMaskTree()
+        .addFieldPath("child.payload.optional_nested_message")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
-    expected.getChildBuilder().getPayloadBuilder().setOptionalNestedMessage(
-        NestedMessage.newBuilder().setBb(5678));
+    expected
+        .getChildBuilder()
+        .getPayloadBuilder()
+        .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
     assertEquals(expected.build(), builder.build());
 
-
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("child.payload.repeated_int32")
+    new FieldMaskTree()
+        .addFieldPath("child.payload.repeated_int32")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
     assertEquals(expected.build(), builder.build());
 
-
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message")
+    new FieldMaskTree()
+        .addFieldPath("child.payload.repeated_nested_message")
         .merge(source, builder, options);
     expected = NestedTestAllTypes.newBuilder();
-    expected.getChildBuilder().getPayloadBuilder().addRepeatedNestedMessage(
-        NestedMessage.newBuilder().setBb(8765));
+    expected
+        .getChildBuilder()
+        .getPayloadBuilder()
+        .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
     assertEquals(expected.build(), builder.build());
-    
+
     // Test merging all fields.
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("child").addFieldPath("payload")
-    .merge(source, builder, options);
+    new FieldMaskTree()
+        .addFieldPath("child")
+        .addFieldPath("payload")
+        .merge(source, builder, options);
     assertEquals(source, builder.build());
-    
+
     // Test repeated options.
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().addRepeatedInt32(1000);
-    new FieldMaskTree().addFieldPath("payload.repeated_int32")
-    .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
     // Default behavior is to append repeated fields.
     assertEquals(2, builder.getPayload().getRepeatedInt32Count());
     assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
     assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
     // Change to replace repeated fields.
     options.setReplaceRepeatedFields(true);
-    new FieldMaskTree().addFieldPath("payload.repeated_int32")
-    .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
     assertEquals(1, builder.getPayload().getRepeatedInt32Count());
     assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
-    
+
     // Test message options.
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
-    new FieldMaskTree().addFieldPath("payload")
-      .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
     // Default behavior is to merge message fields.
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(2000, builder.getPayload().getOptionalUint32());
-    
+
+    // Test merging unset message fields.
+    NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    assertEquals(false, builder.hasPayload());
+
+    // Skip a message field if they are unset in both source and target.
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_int32")
+        .merge(clearedSource, builder, options);
+    assertEquals(false, builder.hasPayload());
+
     // Change to replace message fields.
     options.setReplaceMessageFields(true);
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
-    new FieldMaskTree().addFieldPath("payload")
-      .merge(source, builder, options);
+    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(0, builder.getPayload().getOptionalUint32());
+
+    // Test merging unset message fields.
+    builder = NestedTestAllTypes.newBuilder();
+    builder.getPayloadBuilder().setOptionalInt32(1000);
+    builder.getPayloadBuilder().setOptionalUint32(2000);
+    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    assertEquals(false, builder.hasPayload());
+
+    // Test merging unset primitive fields.
+    builder = source.toBuilder();
+    builder.getPayloadBuilder().clearOptionalInt32();
+    NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build();
+    builder = source.toBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_int32")
+        .merge(sourceWithPayloadInt32Unset, builder, options);
+    assertEquals(true, builder.getPayload().hasOptionalInt32());
+    assertEquals(0, builder.getPayload().getOptionalInt32());
+
+    // Change to clear unset primitive fields.
+    options.setReplacePrimitiveFields(true);
+    builder = source.toBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_int32")
+        .merge(sourceWithPayloadInt32Unset, builder, options);
+    assertEquals(true, builder.hasPayload());
+    assertEquals(false, builder.getPayload().hasOptionalInt32());
   }
 }
-
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 a312fc3..1a99857 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
@@ -41,52 +41,55 @@
   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"));
-    
-    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")));
-    
+    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"));
+
+    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")));
+
     assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload"));
     assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist"));
-    
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
-    
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
+
+    assertTrue(
+        FieldMaskUtil.isValid(
+            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
+    assertFalse(
+        FieldMaskUtil.isValid(
+            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
+
+    assertTrue(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
     // Repeated fields cannot have sub-paths.
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
+    assertFalse(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
     // Non-message fields cannot have sub-paths.
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_int32.bb"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32.bb"));
   }
-  
+
   public void testToString() throws Exception {
     assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance()));
     FieldMask mask = FieldMask.newBuilder().addPaths("foo").build();
     assertEquals("foo", FieldMaskUtil.toString(mask));
     mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build();
     assertEquals("foo,bar", FieldMaskUtil.toString(mask));
-    
+
     // Empty field paths are ignored.
-    mask = FieldMask.newBuilder().addPaths("").addPaths("foo").addPaths("").
-      addPaths("bar").addPaths("").build();
+    mask =
+        FieldMask.newBuilder()
+            .addPaths("")
+            .addPaths("foo")
+            .addPaths("")
+            .addPaths("bar")
+            .addPaths("")
+            .build();
     assertEquals("foo,bar", FieldMaskUtil.toString(mask));
   }
 
@@ -111,8 +114,7 @@
     mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
 
     try {
-      mask = FieldMaskUtil.fromString(
-          NestedTestAllTypes.class, "payload,nonexist");
+      mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, "payload,nonexist");
       fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
       // Expected.
@@ -143,7 +145,33 @@
     } catch (IllegalArgumentException expected) {
     }
   }
-  
+
+  public void testToJsonString() throws Exception {
+    FieldMask mask = FieldMask.getDefaultInstance();
+    assertEquals("", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo").build();
+    assertEquals("foo", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo.bar_baz").addPaths("").build();
+    assertEquals("foo.barBaz", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar_baz").build();
+    assertEquals("foo,barBaz", FieldMaskUtil.toJsonString(mask));
+  }
+
+  public void testFromJsonString() throws Exception {
+    FieldMask mask = FieldMaskUtil.fromJsonString("");
+    assertEquals(0, mask.getPathsCount());
+    mask = FieldMaskUtil.fromJsonString("foo");
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    mask = FieldMaskUtil.fromJsonString("foo.barBaz");
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("foo.bar_baz", mask.getPaths(0));
+    mask = FieldMaskUtil.fromJsonString("foo,barBaz");
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    assertEquals("bar_baz", mask.getPaths(1));
+  }
+
   public void testUnion() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios.
@@ -152,7 +180,16 @@
     FieldMask result = FieldMaskUtil.union(mask1, mask2);
     assertEquals("bar,foo", FieldMaskUtil.toString(result));
   }
-  
+
+  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));
+  }
+
   public void testIntersection() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios.
@@ -161,13 +198,14 @@
     FieldMask result = FieldMaskUtil.intersection(mask1, mask2);
     assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result));
   }
-  
+
   public void testMerge() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testMerge} to cover all scenarios.
-    NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
-        .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
-        .build();
+    NestedTestAllTypes source =
+        NestedTestAllTypes.newBuilder()
+            .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
+            .build();
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
     FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder);
     assertEquals(1234, builder.getPayload().getOptionalInt32());
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 c0eb033..6ef0850 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
@@ -34,6 +34,7 @@
 import com.google.protobuf.BoolValue;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.BytesValue;
+import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.DoubleValue;
 import com.google.protobuf.FloatValue;
 import com.google.protobuf.Int32Value;
@@ -41,6 +42,7 @@
 import com.google.protobuf.InvalidProtocolBufferException;
 import com.google.protobuf.ListValue;
 import com.google.protobuf.Message;
+import com.google.protobuf.NullValue;
 import com.google.protobuf.StringValue;
 import com.google.protobuf.Struct;
 import com.google.protobuf.UInt32Value;
@@ -56,17 +58,30 @@
 import com.google.protobuf.util.JsonTestProto.TestFieldMask;
 import com.google.protobuf.util.JsonTestProto.TestMap;
 import com.google.protobuf.util.JsonTestProto.TestOneof;
+import com.google.protobuf.util.JsonTestProto.TestRecursive;
 import com.google.protobuf.util.JsonTestProto.TestStruct;
 import com.google.protobuf.util.JsonTestProto.TestTimestamp;
 import com.google.protobuf.util.JsonTestProto.TestWrappers;
-
-import junit.framework.TestCase;
-
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+import junit.framework.TestCase;
 
 public class JsonFormatTest extends TestCase {
+  public JsonFormatTest() {
+    // Test that locale does not affect JsonFormat.
+    Locale.setDefault(Locale.forLanguageTag("hi-IN"));
+  }
+
   private void setAllFields(TestAllTypes.Builder builder) {
     builder.setOptionalInt32(1234);
     builder.setOptionalInt64(1234567890123456789L);
@@ -82,7 +97,7 @@
     builder.setOptionalDouble(1.25);
     builder.setOptionalBool(true);
     builder.setOptionalString("Hello world!");
-    builder.setOptionalBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.setOptionalBytes(ByteString.copyFrom(new byte[] {0, 1, 2}));
     builder.setOptionalNestedEnum(NestedEnum.BAR);
     builder.getOptionalNestedMessageBuilder().setValue(100);
 
@@ -100,7 +115,7 @@
     builder.addRepeatedDouble(1.25);
     builder.addRepeatedBool(true);
     builder.addRepeatedString("Hello world!");
-    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {0, 1, 2}));
     builder.addRepeatedNestedEnum(NestedEnum.BAR);
     builder.addRepeatedNestedMessageBuilder().setValue(100);
 
@@ -118,15 +133,15 @@
     builder.addRepeatedDouble(11.25);
     builder.addRepeatedBool(true);
     builder.addRepeatedString("ello world!");
-    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{1, 2}));
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {1, 2}));
     builder.addRepeatedNestedEnum(NestedEnum.BAZ);
     builder.addRepeatedNestedMessageBuilder().setValue(200);
   }
-  
+
   private void assertRoundTripEquals(Message message) throws Exception {
     assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry());
   }
-  
+
   private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception {
     JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
     JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
@@ -135,137 +150,146 @@
     Message parsedMessage = builder.build();
     assertEquals(message.toString(), parsedMessage.toString());
   }
-  
+
   private String toJsonString(Message message) throws IOException {
     return JsonFormat.printer().print(message);
   }
-  
+  private String toCompactJsonString(Message message) throws IOException {
+    return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
+  }
+
   private void mergeFromJson(String json, Message.Builder builder) throws IOException {
     JsonFormat.parser().merge(json, builder);
   }
-  
+
   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));
-    
-    assertRoundTripEquals(message);
-  }
-  
-  public void testUnknownEnumValues() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        .setOptionalNestedEnumValue(12345)
-        .addRepeatedNestedEnumValue(12345)
-        .addRepeatedNestedEnumValue(0)
-        .build();
+
     assertEquals(
         "{\n"
-        + "  \"optionalNestedEnum\": 12345,\n"
-        + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
-        + "}", toJsonString(message));
+            + "  \"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));
+
     assertRoundTripEquals(message);
-    
+  }
+
+  public void testUnknownEnumValues() throws Exception {
+    TestAllTypes message =
+        TestAllTypes.newBuilder()
+            .setOptionalNestedEnumValue(12345)
+            .addRepeatedNestedEnumValue(12345)
+            .addRepeatedNestedEnumValue(0)
+            .build();
+    assertEquals(
+        "{\n"
+            + "  \"optionalNestedEnum\": 12345,\n"
+            + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+            + "}",
+        toJsonString(message));
+    assertRoundTripEquals(message);
+
     TestMap.Builder mapBuilder = TestMap.newBuilder();
-    mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
-    mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
+    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));
+        "{\n"
+            + "  \"int32ToEnumMap\": {\n"
+            + "    \"1\": \"FOO\",\n"
+            + "    \"2\": 12345\n"
+            + "  }\n"
+            + "}",
+        toJsonString(mapMessage));
     assertRoundTripEquals(mapMessage);
   }
-  
+
   public void testSpecialFloatValues() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        .addRepeatedFloat(Float.NaN)
-        .addRepeatedFloat(Float.POSITIVE_INFINITY)
-        .addRepeatedFloat(Float.NEGATIVE_INFINITY)
-        .addRepeatedDouble(Double.NaN)
-        .addRepeatedDouble(Double.POSITIVE_INFINITY)
-        .addRepeatedDouble(Double.NEGATIVE_INFINITY)
-        .build();
+    TestAllTypes message =
+        TestAllTypes.newBuilder()
+            .addRepeatedFloat(Float.NaN)
+            .addRepeatedFloat(Float.POSITIVE_INFINITY)
+            .addRepeatedFloat(Float.NEGATIVE_INFINITY)
+            .addRepeatedDouble(Double.NaN)
+            .addRepeatedDouble(Double.POSITIVE_INFINITY)
+            .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+            .build();
     assertEquals(
         "{\n"
-        + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
-        + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
-        + "}", toJsonString(message));
-    
+            + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
+            + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
+            + "}",
+        toJsonString(message));
+
     assertRoundTripEquals(message);
   }
-  
-  public void testParserAcceptStringForNumbericField() throws Exception {
+
+  public void testParserAcceptStringForNumericField() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
         "{\n"
-        + "  \"optionalInt32\": \"1234\",\n"
-        + "  \"optionalUint32\": \"5678\",\n"
-        + "  \"optionalSint32\": \"9012\",\n"
-        + "  \"optionalFixed32\": \"3456\",\n"
-        + "  \"optionalSfixed32\": \"7890\",\n"
-        + "  \"optionalFloat\": \"1.5\",\n"
-        + "  \"optionalDouble\": \"1.25\",\n"
-        + "  \"optionalBool\": \"true\"\n"
-        + "}", builder);
+            + "  \"optionalInt32\": \"1234\",\n"
+            + "  \"optionalUint32\": \"5678\",\n"
+            + "  \"optionalSint32\": \"9012\",\n"
+            + "  \"optionalFixed32\": \"3456\",\n"
+            + "  \"optionalSfixed32\": \"7890\",\n"
+            + "  \"optionalFloat\": \"1.5\",\n"
+            + "  \"optionalDouble\": \"1.25\",\n"
+            + "  \"optionalBool\": \"true\"\n"
+            + "}",
+        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());
-    assertEquals(1.25, message.getOptionalDouble());
+    assertEquals(1.5f, message.getOptionalFloat(), 0.0f);
+    assertEquals(1.25, message.getOptionalDouble(), 0.0);
     assertEquals(true, message.getOptionalBool());
   }
-  
+
   public void testParserAcceptFloatingPointValueForIntegerField() throws Exception {
     // Test that numeric values like "1.000", "1e5" will also be accepted.
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -275,8 +299,9 @@
             + "  \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
             + "  \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
             + "  \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n"
-            + "}", builder);
-    int[] expectedValues = new int[]{1, 100000, 1, 100000};
+            + "}",
+        builder);
+    int[] expectedValues = new int[] {1, 100000, 1, 100000};
     assertEquals(4, builder.getRepeatedInt32Count());
     assertEquals(4, builder.getRepeatedUint32Count());
     assertEquals(4, builder.getRepeatedInt64Count());
@@ -287,14 +312,14 @@
       assertEquals(expectedValues[i], builder.getRepeatedInt64(i));
       assertEquals(expectedValues[i], builder.getRepeatedUint64(i));
     }
-    
+
     // Non-integers will still be rejected.
     assertRejects("optionalInt32", "1.5");
     assertRejects("optionalUint32", "1.5");
     assertRejects("optionalInt64", "1.5");
     assertRejects("optionalUint64", "1.5");
   }
-  
+
   private void assertRejects(String name, String value) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
@@ -312,7 +337,7 @@
       // Expected.
     }
   }
-  
+
   private void assertAccepts(String name, String value) throws IOException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     // Both numeric form and string form are accepted.
@@ -320,17 +345,17 @@
     builder.clear();
     mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
   }
-  
+
   public void testParserRejectOutOfRangeNumericValues() throws Exception {
     assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE));
     assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE));
     assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L));
     assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L));
-    
+
     assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L));
     assertRejects("optionalUint32", "123456789012345");
     assertRejects("optionalUint32", "-1");
-    
+
     BigInteger one = new BigInteger("1");
     BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE));
     BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE));
@@ -351,7 +376,7 @@
     assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE));
     assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE));
     assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE));
-    
+
     BigDecimal moreThanOne = new BigDecimal("1.000001");
     BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE);
     BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE);
@@ -360,299 +385,304 @@
     assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString());
     assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString());
   }
-  
+
   public void testParserAcceptNull() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
         "{\n"
-        + "  \"optionalInt32\": null,\n"
-        + "  \"optionalInt64\": null,\n"
-        + "  \"optionalUint32\": null,\n"
-        + "  \"optionalUint64\": null,\n"
-        + "  \"optionalSint32\": null,\n"
-        + "  \"optionalSint64\": null,\n"
-        + "  \"optionalFixed32\": null,\n"
-        + "  \"optionalFixed64\": null,\n"
-        + "  \"optionalSfixed32\": null,\n"
-        + "  \"optionalSfixed64\": null,\n"
-        + "  \"optionalFloat\": null,\n"
-        + "  \"optionalDouble\": null,\n"
-        + "  \"optionalBool\": null,\n"
-        + "  \"optionalString\": null,\n"
-        + "  \"optionalBytes\": null,\n"
-        + "  \"optionalNestedMessage\": null,\n"
-        + "  \"optionalNestedEnum\": null,\n"
-        + "  \"repeatedInt32\": null,\n"
-        + "  \"repeatedInt64\": null,\n"
-        + "  \"repeatedUint32\": null,\n"
-        + "  \"repeatedUint64\": null,\n"
-        + "  \"repeatedSint32\": null,\n"
-        + "  \"repeatedSint64\": null,\n"
-        + "  \"repeatedFixed32\": null,\n"
-        + "  \"repeatedFixed64\": null,\n"
-        + "  \"repeatedSfixed32\": null,\n"
-        + "  \"repeatedSfixed64\": null,\n"
-        + "  \"repeatedFloat\": null,\n"
-        + "  \"repeatedDouble\": null,\n"
-        + "  \"repeatedBool\": null,\n"
-        + "  \"repeatedString\": null,\n"
-        + "  \"repeatedBytes\": null,\n"
-        + "  \"repeatedNestedMessage\": null,\n"
-        + "  \"repeatedNestedEnum\": null\n"
-        + "}", builder);
+            + "  \"optionalInt32\": null,\n"
+            + "  \"optionalInt64\": null,\n"
+            + "  \"optionalUint32\": null,\n"
+            + "  \"optionalUint64\": null,\n"
+            + "  \"optionalSint32\": null,\n"
+            + "  \"optionalSint64\": null,\n"
+            + "  \"optionalFixed32\": null,\n"
+            + "  \"optionalFixed64\": null,\n"
+            + "  \"optionalSfixed32\": null,\n"
+            + "  \"optionalSfixed64\": null,\n"
+            + "  \"optionalFloat\": null,\n"
+            + "  \"optionalDouble\": null,\n"
+            + "  \"optionalBool\": null,\n"
+            + "  \"optionalString\": null,\n"
+            + "  \"optionalBytes\": null,\n"
+            + "  \"optionalNestedMessage\": null,\n"
+            + "  \"optionalNestedEnum\": null,\n"
+            + "  \"repeatedInt32\": null,\n"
+            + "  \"repeatedInt64\": null,\n"
+            + "  \"repeatedUint32\": null,\n"
+            + "  \"repeatedUint64\": null,\n"
+            + "  \"repeatedSint32\": null,\n"
+            + "  \"repeatedSint64\": null,\n"
+            + "  \"repeatedFixed32\": null,\n"
+            + "  \"repeatedFixed64\": null,\n"
+            + "  \"repeatedSfixed32\": null,\n"
+            + "  \"repeatedSfixed64\": null,\n"
+            + "  \"repeatedFloat\": null,\n"
+            + "  \"repeatedDouble\": null,\n"
+            + "  \"repeatedBool\": null,\n"
+            + "  \"repeatedString\": null,\n"
+            + "  \"repeatedBytes\": null,\n"
+            + "  \"repeatedNestedMessage\": null,\n"
+            + "  \"repeatedNestedEnum\": null\n"
+            + "}",
+        builder);
     TestAllTypes message = builder.build();
     assertEquals(TestAllTypes.getDefaultInstance(), message);
-    
+
     // Repeated field elements cannot be null.
     try {
       builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"repeatedInt32\": [null, null],\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"repeatedInt32\": [null, null],\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
-    
+
     try {
       builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"repeatedNestedMessage\": [null, null],\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"repeatedNestedMessage\": [null, null],\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
-  
+
+  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());
+  }
+
   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
     // only be fixed by using our own parser. Here we only test the cases where the names are
     // different but still referring to the same field.
-    
-    // Duplicated optional fields. 
+
+    // Duplicated optional fields.
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson(
           "{\n"
               + "  \"optionalNestedMessage\": {},\n"
               + "  \"optional_nested_message\": {}\n"
-          + "}", builder);
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
-    
+
     // Duplicated repeated fields.
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"repeatedNestedMessage\": [null, null],\n"
-          + "  \"repeated_nested_message\": [null, null]\n"
-          + "}", builder);
+              + "  \"repeatedInt32\": [1, 2],\n"
+              + "  \"repeated_int32\": [5, 6]\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
-    
-    // Duplicated oneof fields.
+
+    // Duplicated oneof fields, same name.
+    try {
+      TestOneof.Builder builder = TestOneof.newBuilder();
+      mergeFromJson("{\n" + "  \"oneofInt32\": 1,\n" + "  \"oneof_int32\": 2\n" + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+
+    // Duplicated oneof fields, different name.
     try {
       TestOneof.Builder builder = TestOneof.newBuilder();
       mergeFromJson(
-          "{\n"
-          + "  \"oneofInt32\": 1,\n"
-          + "  \"oneof_int32\": 2\n"
-          + "}", builder);
+          "{\n" + "  \"oneofInt32\": 1,\n" + "  \"oneofNullValue\": null\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
-  
+
   public void testMapFields() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Map().put(1, 10);
-    builder.getMutableInt64ToInt32Map().put(1234567890123456789L, 10);
-    builder.getMutableUint32ToInt32Map().put(2, 20);
-    builder.getMutableUint64ToInt32Map().put(2234567890123456789L, 20);
-    builder.getMutableSint32ToInt32Map().put(3, 30);
-    builder.getMutableSint64ToInt32Map().put(3234567890123456789L, 30);
-    builder.getMutableFixed32ToInt32Map().put(4, 40);
-    builder.getMutableFixed64ToInt32Map().put(4234567890123456789L, 40);
-    builder.getMutableSfixed32ToInt32Map().put(5, 50);
-    builder.getMutableSfixed64ToInt32Map().put(5234567890123456789L, 50);
-    builder.getMutableBoolToInt32Map().put(false, 6);
-    builder.getMutableStringToInt32Map().put("Hello", 10);
+    builder.putInt32ToInt32Map(1, 10);
+    builder.putInt64ToInt32Map(1234567890123456789L, 10);
+    builder.putUint32ToInt32Map(2, 20);
+    builder.putUint64ToInt32Map(2234567890123456789L, 20);
+    builder.putSint32ToInt32Map(3, 30);
+    builder.putSint64ToInt32Map(3234567890123456789L, 30);
+    builder.putFixed32ToInt32Map(4, 40);
+    builder.putFixed64ToInt32Map(4234567890123456789L, 40);
+    builder.putSfixed32ToInt32Map(5, 50);
+    builder.putSfixed64ToInt32Map(5234567890123456789L, 50);
+    builder.putBoolToInt32Map(false, 6);
+    builder.putStringToInt32Map("Hello", 10);
 
-    builder.getMutableInt32ToInt64Map().put(1, 1234567890123456789L);
-    builder.getMutableInt32ToUint32Map().put(2, 20);
-    builder.getMutableInt32ToUint64Map().put(2, 2234567890123456789L);
-    builder.getMutableInt32ToSint32Map().put(3, 30);
-    builder.getMutableInt32ToSint64Map().put(3, 3234567890123456789L);
-    builder.getMutableInt32ToFixed32Map().put(4, 40);
-    builder.getMutableInt32ToFixed64Map().put(4, 4234567890123456789L);
-    builder.getMutableInt32ToSfixed32Map().put(5, 50);
-    builder.getMutableInt32ToSfixed64Map().put(5, 5234567890123456789L);
-    builder.getMutableInt32ToFloatMap().put(6, 1.5f);
-    builder.getMutableInt32ToDoubleMap().put(6, 1.25);
-    builder.getMutableInt32ToBoolMap().put(7, false);
-    builder.getMutableInt32ToStringMap().put(7, "World");
-    builder.getMutableInt32ToBytesMap().put(
-        8, ByteString.copyFrom(new byte[]{1, 2, 3}));
-    builder.getMutableInt32ToMessageMap().put(
-        8, NestedMessage.newBuilder().setValue(1234).build());
-    builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR);
+    builder.putInt32ToInt64Map(1, 1234567890123456789L);
+    builder.putInt32ToUint32Map(2, 20);
+    builder.putInt32ToUint64Map(2, 2234567890123456789L);
+    builder.putInt32ToSint32Map(3, 30);
+    builder.putInt32ToSint64Map(3, 3234567890123456789L);
+    builder.putInt32ToFixed32Map(4, 40);
+    builder.putInt32ToFixed64Map(4, 4234567890123456789L);
+    builder.putInt32ToSfixed32Map(5, 50);
+    builder.putInt32ToSfixed64Map(5, 5234567890123456789L);
+    builder.putInt32ToFloatMap(6, 1.5f);
+    builder.putInt32ToDoubleMap(6, 1.25);
+    builder.putInt32ToBoolMap(7, false);
+    builder.putInt32ToStringMap(7, "World");
+    builder.putInt32ToBytesMap(8, ByteString.copyFrom(new byte[] {1, 2, 3}));
+    builder.putInt32ToMessageMap(8, NestedMessage.newBuilder().setValue(1234).build());
+    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));
+            + "  \"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));
     assertRoundTripEquals(message);
-    
+
     // Test multiple entries.
     builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Map().put(1, 2);
-    builder.getMutableInt32ToInt32Map().put(3, 4);
+    builder.putInt32ToInt32Map(1, 2);
+    builder.putInt32ToInt32Map(3, 4);
     message = builder.build();
-    
+
     assertEquals(
-        "{\n"
-        + "  \"int32ToInt32Map\": {\n"
-        + "    \"1\": 2,\n"
-        + "    \"3\": 4\n"
-        + "  }\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"int32ToInt32Map\": {\n" + "    \"1\": 2,\n" + "    \"3\": 4\n" + "  }\n" + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
   }
-  
+
   public void testMapNullValueIsRejected() throws Exception {
     try {
       TestMap.Builder builder = TestMap.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"int32ToInt32Map\": {null: 1},\n"
-          + "  \"int32ToMessageMap\": {null: 2}\n"
-          + "}", builder);
+              + "  \"int32ToInt32Map\": {null: 1},\n"
+              + "  \"int32ToMessageMap\": {null: 2}\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
-    
+
     try {
       TestMap.Builder builder = TestMap.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"int32ToInt32Map\": {\"1\": null},\n"
-          + "  \"int32ToMessageMap\": {\"2\": null}\n"
-          + "}", builder);
+              + "  \"int32ToInt32Map\": {\"1\": null},\n"
+              + "  \"int32ToMessageMap\": {\"2\": null}\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
-  
+
   public void testParserAcceptNonQuotedObjectKey() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     mergeFromJson(
-        "{\n"
-        + "  int32ToInt32Map: {1: 2},\n"
-        + "  stringToInt32Map: {hello: 3}\n"
-        + "}", builder);
+        "{\n" + "  int32ToInt32Map: {1: 2},\n" + "  stringToInt32Map: {hello: 3}\n" + "}", builder);
     TestMap message = builder.build();
     assertEquals(2, message.getInt32ToInt32Map().get(1).intValue());
     assertEquals(3, message.getStringToInt32Map().get("hello").intValue());
   }
-  
+
   public void testWrappers() throws Exception {
     TestWrappers.Builder builder = TestWrappers.newBuilder();
     builder.getBoolValueBuilder().setValue(false);
@@ -665,19 +695,20 @@
     builder.getStringValueBuilder().setValue("");
     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));
+            + "  \"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));
     assertRoundTripEquals(message);
 
     builder = TestWrappers.newBuilder();
@@ -689,110 +720,107 @@
     builder.getFloatValueBuilder().setValue(5.0f);
     builder.getDoubleValueBuilder().setValue(6.0);
     builder.getStringValueBuilder().setValue("7");
-    builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8}));
+    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));
+            + "  \"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));
     assertRoundTripEquals(message);
   }
-  
+
   public void testTimestamp() throws Exception {
-    TestTimestamp message = TestTimestamp.newBuilder()
-        .setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z"))
-        .build();
-    
+    TestTimestamp message =
+        TestTimestamp.newBuilder()
+            .setTimestampValue(Timestamps.parse("1970-01-01T00:00:00Z"))
+            .build();
+
     assertEquals(
-        "{\n"
-        + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
-  
+
   public void testDuration() throws Exception {
-    TestDuration message = TestDuration.newBuilder()
-        .setDurationValue(TimeUtil.parseDuration("12345s"))
-        .build();
-    
-    assertEquals(
-        "{\n"
-        + "  \"durationValue\": \"12345s\"\n"
-        + "}", toJsonString(message));
+    TestDuration message =
+        TestDuration.newBuilder().setDurationValue(Durations.parse("12345s")).build();
+
+    assertEquals("{\n" + "  \"durationValue\": \"12345s\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
-  
+
   public void testFieldMask() throws Exception {
-    TestFieldMask message = TestFieldMask.newBuilder()
-        .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz"))
-        .build();
-    
+    TestFieldMask message =
+        TestFieldMask.newBuilder()
+            .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz,foo_bar.baz"))
+            .build();
+
     assertEquals(
-        "{\n"
-        + "  \"fieldMaskValue\": \"foo.bar,baz\"\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"fieldMaskValue\": \"foo.bar,baz,fooBar.baz\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
-  
+
   public void testStruct() throws Exception {
     // Build a struct with all possible values.
     TestStruct.Builder builder = TestStruct.newBuilder();
     Struct.Builder structBuilder = builder.getStructValueBuilder();
-    structBuilder.getMutableFields().put(
-        "null_value", Value.newBuilder().setNullValueValue(0).build());
-    structBuilder.getMutableFields().put(
-        "number_value", Value.newBuilder().setNumberValue(1.25).build());
-    structBuilder.getMutableFields().put(
-        "string_value", Value.newBuilder().setStringValue("hello").build());
+    structBuilder.putFields("null_value", Value.newBuilder().setNullValueValue(0).build());
+    structBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1.25).build());
+    structBuilder.putFields("string_value", Value.newBuilder().setStringValue("hello").build());
     Struct.Builder subStructBuilder = Struct.newBuilder();
-    subStructBuilder.getMutableFields().put(
-        "number_value", Value.newBuilder().setNumberValue(1234).build());
-    structBuilder.getMutableFields().put(
+    subStructBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1234).build());
+    structBuilder.putFields(
         "struct_value", Value.newBuilder().setStructValue(subStructBuilder.build()).build());
     ListValue.Builder listBuilder = ListValue.newBuilder();
     listBuilder.addValues(Value.newBuilder().setNumberValue(1.125).build());
     listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
-    structBuilder.getMutableFields().put(
+    structBuilder.putFields(
         "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));
+            + "  \"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));
     assertRoundTripEquals(message);
-    
+
     builder = TestStruct.newBuilder();
     builder.setValue(Value.newBuilder().setNullValueValue(0).build());
     message = builder.build();
-    assertEquals(
-        "{\n"
-        + "  \"value\": null\n"
-        + "}", toJsonString(message));
+    assertEquals("{\n" + "  \"value\": null\n" + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    builder = TestStruct.newBuilder();
+    listBuilder = builder.getListValueBuilder();
+    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));
     assertRoundTripEquals(message);
   }
-  
+
   public void testAnyFields() throws Exception {
     TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
     TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
-    
+
     // A TypeRegistry must be provided in order to convert Any types.
     try {
       toJsonString(message);
@@ -800,186 +828,295 @@
     } catch (IOException e) {
       // Expected.
     }
-    
-    JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder()
-        .add(TestAllTypes.getDescriptor()).build();
+
+    JsonFormat.TypeRegistry registry =
+        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));
+            + "  \"anyValue\": {\n"
+            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+            + "    \"optionalInt32\": 1234\n"
+            + "  }\n"
+            + "}",
+        printer.print(message));
     assertRoundTripEquals(message, registry);
-    
-    
+
+    TestAny messageWithDefaultAnyValue =
+        TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build();
+    assertEquals(
+        "{\n"
+            + "  \"anyValue\": {}\n"
+            + "}",
+        printer.print(messageWithDefaultAnyValue));
+    assertRoundTripEquals(messageWithDefaultAnyValue, registry);
+
     // Well-known types have a special formatting when embedded in Any.
     //
     // 1. Any in Any.
     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));
+            + "  \"@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));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+            + "  \"value\": 12345\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
+            + "  \"value\": 12345\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+            + "  \"value\": \"12345\"\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
+            + "  \"value\": \"12345\"\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
+            + "  \"value\": 12345.0\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
+            + "  \"value\": 12345.0\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+            + "  \"value\": true\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
+            + "  \"value\": \"Hello\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(BytesValue.newBuilder().setValue(
-        ByteString.copyFrom(new byte[]{1, 2})).build());
+    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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
+            + "  \"value\": \"AQI=\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
-    
+
     // 3. Timestamp in Any.
-    anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z"));
+    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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+            + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
-    
+
     // 4. Duration in Any
-    anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s"));
+    anyMessage = Any.pack(Durations.parse("12345.10s"));
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
-        + "  \"value\": \"12345.100s\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+            + "  \"value\": \"12345.100s\"\n"
+            + "}",
+        printer.print(anyMessage));
     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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+            + "  \"value\": \"foo.bar,baz\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 6. Struct in Any
     Struct.Builder structBuilder = Struct.newBuilder();
-    structBuilder.getMutableFields().put(
-        "number", Value.newBuilder().setNumberValue(1.125).build());
+    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));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+            + "  \"value\": {\n"
+            + "    \"number\": 1.125\n"
+            + "  }\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
+
+    // 7. Value (number type) in Any
     Value.Builder valueBuilder = Value.newBuilder();
     valueBuilder.setNumberValue(1);
     anyMessage = Any.pack(valueBuilder.build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-        + "  \"value\": 1.0\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+            + "  \"value\": 1.0\n"
+            + "}",
+        printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 8. Value (null type) in Any
+    anyMessage = Any.pack(Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
+    assertEquals(
+        "{\n"
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+            + "  \"value\": null\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
   }
-  
+
+  public void testAnyInMaps() throws Exception {
+    JsonFormat.TypeRegistry registry =
+        JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
+    JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
+
+    TestAny.Builder testAny = TestAny.newBuilder();
+    testAny.putAnyMap("int32_wrapper", Any.pack(Int32Value.newBuilder().setValue(123).build()));
+    testAny.putAnyMap("int64_wrapper", Any.pack(Int64Value.newBuilder().setValue(456).build()));
+    testAny.putAnyMap("timestamp", Any.pack(Timestamps.parse("1969-12-31T23:59:59Z")));
+    testAny.putAnyMap("duration", Any.pack(Durations.parse("12345.1s")));
+    testAny.putAnyMap("field_mask", Any.pack(FieldMaskUtil.fromString("foo.bar,baz")));
+    Value numberValue = Value.newBuilder().setNumberValue(1.125).build();
+    Struct.Builder struct = Struct.newBuilder();
+    struct.putFields("number", numberValue);
+    testAny.putAnyMap("struct", Any.pack(struct.build()));
+    Value nullValue = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build();
+    testAny.putAnyMap(
+        "list_value",
+        Any.pack(ListValue.newBuilder().addValues(numberValue).addValues(nullValue).build()));
+    testAny.putAnyMap("number_value", Any.pack(numberValue));
+    testAny.putAnyMap("any_value_number", Any.pack(Any.pack(numberValue)));
+    testAny.putAnyMap("any_value_default", Any.pack(Any.getDefaultInstance()));
+    testAny.putAnyMap("default", Any.getDefaultInstance());
+
+    assertEquals(
+        "{\n"
+            + "  \"anyMap\": {\n"
+            + "    \"int32_wrapper\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+            + "      \"value\": 123\n"
+            + "    },\n"
+            + "    \"int64_wrapper\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+            + "      \"value\": \"456\"\n"
+            + "    },\n"
+            + "    \"timestamp\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+            + "      \"value\": \"1969-12-31T23:59:59Z\"\n"
+            + "    },\n"
+            + "    \"duration\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+            + "      \"value\": \"12345.100s\"\n"
+            + "    },\n"
+            + "    \"field_mask\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+            + "      \"value\": \"foo.bar,baz\"\n"
+            + "    },\n"
+            + "    \"struct\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+            + "      \"value\": {\n"
+            + "        \"number\": 1.125\n"
+            + "      }\n"
+            + "    },\n"
+            + "    \"list_value\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.ListValue\",\n"
+            + "      \"value\": [1.125, null]\n"
+            + "    },\n"
+            + "    \"number_value\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+            + "      \"value\": 1.125\n"
+            + "    },\n"
+            + "    \"any_value_number\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+            + "      \"value\": {\n"
+            + "        \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+            + "        \"value\": 1.125\n"
+            + "      }\n"
+            + "    },\n"
+            + "    \"any_value_default\": {\n"
+            + "      \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+            + "      \"value\": {}\n"
+            + "    },\n"
+            + "    \"default\": {}\n"
+            + "  }\n"
+            + "}",
+        printer.print(testAny.build()));
+    assertRoundTripEquals(testAny.build(), registry);
+  }
+
   public void testParserMissingTypeUrl() throws Exception {
     try {
       Any.Builder builder = Any.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalInt32\": 1234\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalInt32\": 1234\n" + "}", builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
     }
   }
-  
+
   public void testParserUnexpectedTypeUrl() throws Exception {
     try {
-      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      Any.Builder builder = Any.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-          + "  \"optionalInt32\": 12345\n"
-          + "}", builder);
+              + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+              + "  \"optionalInt32\": 12345\n"
+              + "}",
+          builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
-    } 
+    }
   }
-  
+
   public void testParserRejectTrailingComma() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalInt32\": 12345,\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalInt32\": 12345,\n" + "}", builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
@@ -1000,24 +1137,49 @@
     //   // Expected.
     // }
   }
-  
+
   public void testParserRejectInvalidBase64() throws Exception {
     assertRejects("optionalBytes", "!@#$");
-    // We use standard BASE64 with paddings.
-    assertRejects("optionalBytes", "AQI");
   }
-  
+
+  public void testParserAcceptBase64Variants() throws Exception {
+    assertAccepts("optionalBytes", "AQI");  // No padding
+    assertAccepts("optionalBytes", "-_w");  // base64Url, no padding
+  }
+
   public void testParserRejectInvalidEnumValue() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalNestedEnum\": \"XXX\"\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalNestedEnum\": \"XXX\"\n" + "}", builder);
       fail("Exception is expected.");
     } catch (InvalidProtocolBufferException e) {
       // Expected.
-    } 
+    }
+  }
+
+  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.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testParserIgnoringUnknownFields() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
+    JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
+  }
+
+  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());
   }
 
   public void testCustomJsonName() throws Exception {
@@ -1026,6 +1188,12 @@
     assertRoundTripEquals(message);
   }
 
+  public void testDefaultGsonDoesNotHtmlEscape() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build();
+    assertEquals(
+        "{\n" + "  \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message));
+  }
+
   public void testIncludingDefaultValueFields() throws Exception {
     TestAllTypes message = TestAllTypes.getDefaultInstance();
     assertEquals("{\n}", JsonFormat.printer().print(message));
@@ -1067,6 +1235,115 @@
             + "}",
         JsonFormat.printer().includingDefaultValueFields().print(message));
 
+    Set<FieldDescriptor> fixedFields = new HashSet<FieldDescriptor>();
+    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));
+
+    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));
+
+    try {
+      JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields();
+      fail("IllegalStateException is expected.");
+    } catch (IllegalStateException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    try {
+      JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields(fixedFields);
+      fail("IllegalStateException is expected.");
+    } catch (IllegalStateException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    try {
+      JsonFormat.printer().includingDefaultValueFields(fixedFields).includingDefaultValueFields();
+      fail("IllegalStateException is expected.");
+    } catch (IllegalStateException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    try {
+      JsonFormat.printer()
+          .includingDefaultValueFields(fixedFields)
+          .includingDefaultValueFields(fixedFields);
+      fail("IllegalStateException is expected.");
+    } catch (IllegalStateException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    Set<FieldDescriptor> intFields = new HashSet<FieldDescriptor>();
+    for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) {
+      if (fieldDesc.getName().contains("_int")) {
+        intFields.add(fieldDesc);
+      }
+    }
+
+    try {
+      JsonFormat.printer()
+          .includingDefaultValueFields(intFields)
+          .includingDefaultValueFields(fixedFields);
+      fail("IllegalStateException is expected.");
+    } catch (IllegalStateException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    try {
+      JsonFormat.printer().includingDefaultValueFields(null);
+      fail("IllegalArgumentException is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
+    try {
+      JsonFormat.printer().includingDefaultValueFields(Collections.<FieldDescriptor>emptySet());
+      fail("IllegalArgumentException is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+      assertTrue(
+          "Exception message should mention includingDefaultValueFields.",
+          e.getMessage().contains("includingDefaultValueFields"));
+    }
+
     TestMap mapMessage = TestMap.getDefaultInstance();
     assertEquals("{\n}", JsonFormat.printer().print(mapMessage));
     assertEquals(
@@ -1129,6 +1406,24 @@
             + "  }\n"
             + "}",
         JsonFormat.printer().includingDefaultValueFields().print(mapMessage));
+
+    TestOneof oneofMessage = TestOneof.getDefaultInstance();
+    assertEquals("{\n}", JsonFormat.printer().print(oneofMessage));
+    assertEquals("{\n}", JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
+
+    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));
+
+    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));
   }
 
   public void testPreservingProtoFieldNames() throws Exception {
@@ -1153,4 +1448,145 @@
     JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder);
     assertEquals(54321, builder.getOptionalInt32());
   }
+
+  public void testPrintingEnumsAsInts() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
+    assertEquals(
+        "{\n" + "  \"optionalNestedEnum\": 1\n" + "}",
+        JsonFormat.printer().printingEnumsAsInts().print(message));
+  }
+
+  public void testOmittingInsignificantWhiteSpace() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
+    assertEquals(
+        "{" + "\"optionalInt32\":12345" + "}",
+        JsonFormat.printer().omittingInsignificantWhitespace().print(message));
+    TestAllTypes message1 = TestAllTypes.getDefaultInstance();
+    assertEquals("{}", JsonFormat.printer().omittingInsignificantWhitespace().print(message1));
+    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));
+  }
+
+  // Regression test for b/29892357
+  public void testEmptyWrapperTypesInAny() throws Exception {
+    JsonFormat.TypeRegistry registry =
+        JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
+    JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
+
+    Any.Builder builder = Any.newBuilder();
+    parser.merge(
+        "{\n"
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+            + "  \"value\": false\n"
+            + "}\n",
+        builder);
+    Any any = builder.build();
+    assertEquals(0, any.getValue().size());
+  }
+
+  public void testRecursionLimit() throws Exception {
+    String input =
+        "{\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());
+
+    parser = JsonFormat.parser().usingRecursionLimit(3);
+    builder = TestRecursive.newBuilder();
+    try {
+      parser.merge(input, builder);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  // Test that we are not leaking out JSON exceptions.
+  public void testJsonException() throws Exception {
+    InputStream throwingInputStream =
+        new InputStream() {
+          public int read() throws IOException {
+            throw new IOException("12345");
+          }
+        };
+    InputStreamReader throwingReader = new InputStreamReader(throwingInputStream);
+    // When the underlying reader throws IOException, JsonFormat should forward
+    // through this IOException.
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      JsonFormat.parser().merge(throwingReader, builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      assertEquals("12345", e.getMessage());
+    }
+
+    Reader invalidJsonReader = new StringReader("{ xxx - yyy }");
+    // When the JSON parser throws parser exceptions, JsonFormat should turn
+    // that into InvalidProtocolBufferException.
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      JsonFormat.parser().merge(invalidJsonReader, builder);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
 }
diff --git a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
index 4c31b2b..5af83d8 100644
--- a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
@@ -32,14 +32,11 @@
 
 import com.google.protobuf.Duration;
 import com.google.protobuf.Timestamp;
-
-import junit.framework.TestCase;
-
-import org.junit.Assert;
-
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.List;
+import junit.framework.TestCase;
+import org.junit.Assert;
 
 /** Unit tests for {@link TimeUtil}. */
 public class TimeUtilTest extends TestCase {
@@ -84,6 +81,7 @@
   private class ParseTimestampThread extends Thread {
     private final String[] strings;
     private final Timestamp[] values;
+
     public ParseTimestampThread(String[] strings, Timestamp[] values) {
       this.strings = strings;
       this.values = values;
@@ -102,8 +100,8 @@
         }
         if (result.getSeconds() != values[index].getSeconds()
             || result.getNanos() != values[index].getNanos()) {
-          errorMessage = "Actual result: " + result.toString() + ", expected: "
-              + values[index].toString();
+          errorMessage =
+              "Actual result: " + result.toString() + ", expected: " + values[index].toString();
           break;
         }
         index = (index + 1) % strings.length;
@@ -112,26 +110,26 @@
   }
 
   public void testTimestampConcurrentParsing() throws Exception {
-    String[] timestampStrings = new String[]{
-      "0001-01-01T00:00:00Z",
-      "9999-12-31T23:59:59.999999999Z",
-      "1970-01-01T00:00:00Z",
-      "1969-12-31T23:59:59.999Z",
-    };
+    String[] timestampStrings =
+        new String[] {
+          "0001-01-01T00:00:00Z",
+          "9999-12-31T23:59:59.999999999Z",
+          "1970-01-01T00:00:00Z",
+          "1969-12-31T23:59:59.999Z",
+        };
     Timestamp[] timestampValues = new Timestamp[timestampStrings.length];
     for (int i = 0; i < timestampStrings.length; i++) {
       timestampValues[i] = TimeUtil.parseTimestamp(timestampStrings[i]);
     }
 
     final int THREAD_COUNT = 16;
-    final int RUNNING_TIME = 5000;  // in milliseconds.
+    final int RUNNING_TIME = 5000; // in milliseconds.
     final List<Thread> threads = new ArrayList<Thread>();
 
     stopParsingThreads = false;
     errorMessage = "";
     for (int i = 0; i < THREAD_COUNT; i++) {
-      Thread thread = new ParseTimestampThread(
-          timestampStrings, timestampValues);
+      Thread thread = new ParseTimestampThread(timestampStrings, timestampValues);
       thread.start();
       threads.add(thread);
     }
@@ -146,8 +144,8 @@
   public void testTimetampInvalidFormat() throws Exception {
     try {
       // Value too small.
-      Timestamp value = Timestamp.newBuilder()
-        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MIN - 1).build();
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(TimeUtil.TIMESTAMP_SECONDS_MIN - 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -156,14 +154,14 @@
 
     try {
       // Value too large.
-      Timestamp value = Timestamp.newBuilder()
-        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MAX + 1).build();
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(TimeUtil.TIMESTAMP_SECONDS_MAX + 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
       // Expected.
     }
-    
+
     try {
       // Invalid nanos value.
       Timestamp value = Timestamp.newBuilder().setNanos(-1).build();
@@ -279,8 +277,7 @@
   public void testDurationInvalidFormat() throws Exception {
     try {
       // Value too small.
-      Duration value = Duration.newBuilder()
-        .setSeconds(TimeUtil.DURATION_SECONDS_MIN - 1).build();
+      Duration value = Duration.newBuilder().setSeconds(TimeUtil.DURATION_SECONDS_MIN - 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -289,18 +286,7 @@
 
     try {
       // Value too large.
-      Duration value = Duration.newBuilder()
-        .setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
-      TimeUtil.toString(value);
-      Assert.fail("Exception is expected.");
-    } catch (IllegalArgumentException e) {
-      // Expected.
-    }
-    
-    try {
-      // Invalid nanos value.
-      Duration value = Duration.newBuilder().setSeconds(1).setNanos(-1)
-          .build();
+      Duration value = Duration.newBuilder().setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -309,8 +295,16 @@
 
     try {
       // Invalid nanos value.
-      Duration value = Duration.newBuilder().setSeconds(-1).setNanos(1)
-          .build();
+      Duration value = Duration.newBuilder().setSeconds(1).setNanos(-1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid nanos value.
+      Duration value = Duration.newBuilder().setSeconds(-1).setNanos(1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -367,8 +361,7 @@
   }
 
   public void testTimestampConversion() throws Exception {
-    Timestamp timestamp =
-      TimeUtil.parseTimestamp("1970-01-01T00:00:01.111111111Z");
+    Timestamp timestamp = TimeUtil.parseTimestamp("1970-01-01T00:00:01.111111111Z");
     assertEquals(1111111111, TimeUtil.toNanos(timestamp));
     assertEquals(1111111, TimeUtil.toMicros(timestamp));
     assertEquals(1111, TimeUtil.toMillis(timestamp));
@@ -378,7 +371,7 @@
     assertEquals("1970-01-01T00:00:01.111111Z", TimeUtil.toString(timestamp));
     timestamp = TimeUtil.createTimestampFromMillis(1111);
     assertEquals("1970-01-01T00:00:01.111Z", TimeUtil.toString(timestamp));
-    
+
     timestamp = TimeUtil.parseTimestamp("1969-12-31T23:59:59.111111111Z");
     assertEquals(-888888889, TimeUtil.toNanos(timestamp));
     assertEquals(-888889, TimeUtil.toMicros(timestamp));
@@ -402,7 +395,7 @@
     assertEquals("1.111111s", TimeUtil.toString(duration));
     duration = TimeUtil.createDurationFromMillis(1111);
     assertEquals("1.111s", TimeUtil.toString(duration));
-    
+
     duration = TimeUtil.parseDuration("-1.111111111s");
     assertEquals(-1111111111, TimeUtil.toNanos(duration));
     assertEquals(-1111111, TimeUtil.toMicros(duration));
@@ -459,29 +452,28 @@
 
     duration = TimeUtil.add(duration, duration);
     assertEquals("-2.250s", TimeUtil.toString(duration));
-    
+
     duration = TimeUtil.subtract(duration, TimeUtil.parseDuration("-1s"));
     assertEquals("-1.250s", TimeUtil.toString(duration));
-    
+
     // Multiplications (with results larger than Long.MAX_VALUE in nanoseconds).
     duration = TimeUtil.parseDuration("0.999999999s");
-    assertEquals("315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    assertEquals(
+        "315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
     duration = TimeUtil.parseDuration("-0.999999999s");
-    assertEquals("-315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
-    assertEquals("315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, -315576000000L)));
-    
+    assertEquals(
+        "-315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    assertEquals(
+        "315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, -315576000000L)));
+
     // Divisions (with values larger than Long.MAX_VALUE in nanoseconds).
     Duration d1 = TimeUtil.parseDuration("315576000000s");
     Duration d2 = TimeUtil.subtract(d1, TimeUtil.createDurationFromNanos(1));
     assertEquals(1, TimeUtil.divide(d1, d2));
     assertEquals(0, TimeUtil.divide(d2, d1));
     assertEquals("0.000000001s", TimeUtil.toString(TimeUtil.remainder(d1, d2)));
-    assertEquals("315575999999.999999999s",
-      TimeUtil.toString(TimeUtil.remainder(d2, d1)));
-    
+    assertEquals("315575999999.999999999s", TimeUtil.toString(TimeUtil.remainder(d2, d1)));
+
     // Divisions involving negative values.
     //
     // (-5) / 2 = -2, remainder = -1
diff --git a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
index 509c1d6..d1248cf 100644
--- a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
@@ -94,6 +94,7 @@
   oneof oneof_field {
     int32 oneof_int32 = 1;
     TestAllTypes.NestedMessage oneof_nested_message = 2;
+    google.protobuf.NullValue oneof_null_value = 3;
   }
 }
 
@@ -159,12 +160,19 @@
 message TestStruct {
   google.protobuf.Struct struct_value = 1;
   google.protobuf.Value value = 2;
+  google.protobuf.ListValue list_value = 3;
 }
 
 message TestAny {
   google.protobuf.Any any_value = 1;
+  map<string, google.protobuf.Any> any_map = 2;
 }
 
 message TestCustomJsonName {
   int32 value = 1 [json_name = "@value"];
 }
+
+message TestRecursive {
+  int32 value = 1;
+  TestRecursive nested = 2;
+}