From 32f5d0178c216a0f748edafa8bd31b2150aa6502 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 20 Feb 2015 14:45:45 -0800 Subject: Add changelog for 3.0.0-alpha2 release. Change-Id: I4cbb3374e351c31611de472c7d5d78e4ce2b0f3b --- CHANGES.txt | 40 ++++++++++++++++++++++++++++++++++++++++ javanano/README.txt | 22 ++++++++++++---------- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0d4ce0ec..02c964cb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,43 @@ +2015-2-22 version 3.0.0-alpha-2 (Ruby/JavaNano): + General + * Introduced two new language implementations (Ruby and JavaNano) to proto3. + * Various bug fixes since 3.0.0-alpha-1 + + Ruby: + TODO(cfallin): Add descriptions here. + + JavaNano: + JavaNano is a special code generator and runtime library designed especially + for resource-restricted systems, like Android. It is very resource-friendly + in both the amount of code and the runtime overhead. Here is an an overview + of JavaNano features compared with the official Java protobuf: + + - No descriptors or message builders. + - All messages are mutable; fields are public Java fields. + - For optional fields only, encapsulation behind setter/getter/hazzer/ + clearer functions is opt-in, which provide proper 'has' state support. + - For proto2, if not opted in, has state (field presence) is not available. + Serialization outputs all fields not equal to their defaults. + The behavior is consistent with proto3 semantics. + - Required fields (proto2 only) are always serialized. + - Enum constants are integers; protection against invalid values only + when parsing from the wire. + - Enum constants can be generated into container interfaces bearing + the enum's name (so the referencing code is in Java style). + - CodedInputByteBufferNano can only take byte[] (not InputStream). + - Similarly CodedOutputByteBufferNano can only write to byte[]. + - Repeated fields are in arrays, not ArrayList or Vector. Null array + elements are allowed and silently ignored. + - Full support for serializing/deserializing repeated packed fields. + - Support extensions (in proto2). + - Unset messages/groups are null, not an immutable empty default + instance. + - toByteArray(...) and mergeFrom(...) are now static functions of + MessageNano. + - The 'bytes' type translates to the Java type byte[]. + + See javanano/README.txt for details. + 2014-12-01 version 3.0.0-alpha-1 (C++/Java): General diff --git a/javanano/README.txt b/javanano/README.txt index 5a05b865..cfb3c3b4 100644 --- a/javanano/README.txt +++ b/javanano/README.txt @@ -68,18 +68,20 @@ running unit tests. Nano version ============================ -Nano is a special code generator and runtime library designed specially -for Android, and is very resource-friendly in both the amount of code -and the runtime overhead. An overview of Nano features: +JavaNano is a special code generator and runtime library designed specially for +resource-restricted systems, like Android. It is very resource-friendly in both +the amount of code and the runtime overhead. Here is an overview of JavaNano +features compared with the official Java protobuf: - No descriptors or message builders. - All messages are mutable; fields are public Java fields. - For optional fields only, encapsulation behind setter/getter/hazzer/ clearer functions is opt-in, which provide proper 'has' state support. -- If not opted in, has state is not available. Serialization outputs - all fields not equal to their defaults (see important implications - below). -- Required fields are always serialized. +- For proto2, if not opted in, has state (field presence) is not available. + Serialization outputs all fields not equal to their defaults + (see important implications below). + The behavior is consistent with proto3 semantics. +- Required fields (proto2 only) are always serialized. - Enum constants are integers; protection against invalid values only when parsing from the wire. - Enum constants can be generated into container interfaces bearing @@ -88,8 +90,8 @@ and the runtime overhead. An overview of Nano features: - Similarly CodedOutputByteBufferNano can only write to byte[]. - Repeated fields are in arrays, not ArrayList or Vector. Null array elements are allowed and silently ignored. -- Full support of serializing/deserializing repeated packed fields. -- Support of extensions. +- Full support for serializing/deserializing repeated packed fields. +- Support extensions (in proto2). - Unset messages/groups are null, not an immutable empty default instance. - toByteArray(...) and mergeFrom(...) are now static functions of @@ -200,7 +202,7 @@ optional_field_style={default,accessors,reftypes} (default: default) In the default style, optional fields translate into public mutable Java fields, and the serialization process is as discussed in the - "IMPORTANT" section above. + "IMPORTANT" section above. * accessors * -- cgit v1.2.3 From 1d4f321327dd0826211e0efb983a1087310a2ce3 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 20 Feb 2015 17:32:06 -0800 Subject: Updated CHANGES.txt to mention Ruby extension. Change-Id: I3c3ec4aecf4ea2ce786d8d674baeca875e71801f --- CHANGES.txt | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 02c964cb..e0c02084 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,10 +1,35 @@ -2015-2-22 version 3.0.0-alpha-2 (Ruby/JavaNano): +2015-02-22 version 3.0.0-alpha-2 (Ruby/JavaNano): General * Introduced two new language implementations (Ruby and JavaNano) to proto3. * Various bug fixes since 3.0.0-alpha-1 Ruby: - TODO(cfallin): Add descriptions here. + We have added proto3 support for Ruby via a native C extension. + + The Ruby extension itself is included in the ruby/ directory, and details on + building and installing the extension are in ruby/README.md. The extension + will also be published as a Ruby gem. Code generator support is included as + part of `protoc` with the `--ruby_out` flag. + + The Ruby extension implements a user-friendly DSL to define message types + (also generated by the code generator from `.proto` files). Once a message + type is defined, the user may create instances of the message that behave in + ways idiomatic to Ruby. For example: + + - Message fields are present as ordinary Ruby properties (getter method + `foo` and setter method `foo=`). + - Repeated field elements are stored in a container that acts like a native + Ruby array, and map elements are stored in a container that acts like a + native Ruby hashmap. + - The usual well-known methods, such as `#to_s`, `#dup`, and the like, are + present. + + Unlike several existing third-party Ruby extensions for protobuf, this + extension is built on a "strongly-typed" philosophy: message fields and + array/map containers will throw exceptions eagerly when values of the + incorrect type are inserted. + + See ruby/README.md for details. JavaNano: JavaNano is a special code generator and runtime library designed especially -- cgit v1.2.3 From 6ad8f547fee97798c11b37f5e887d02b6f3c8a2a Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 20 Feb 2015 17:49:14 -0800 Subject: Updated Ruby README. Change-Id: I8c3717f549c9b4e9d07c77ec5875c9cd62b296ac --- ruby/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ruby/README.md b/ruby/README.md index 88e9c0e1..59d5ace8 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -16,7 +16,6 @@ To build this Ruby extension, you will need: * Bundler * Ruby development headers * a C compiler -* the upb submodule First, install the required Ruby gems: -- cgit v1.2.3 From 11ad1bd277237907a2b8683f7a8b4a92f1d1163b Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 20 Feb 2015 18:06:31 -0800 Subject: Update Ruby gem version to 3.0.0.alpha.2.0. This update conforms to our two-numbers-after-alpha scheme that allows us to bump the last number if we need to re-upload a gem. (Rubygems does not allow re-use of a version number once a gem is uploaded.) Change-Id: Ia8e7c129d19800afd66f8052785cf5a00462c7ba --- ruby/google-protobuf.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 7bfa533c..e294751f 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -7,7 +7,7 @@ end Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.0.0.alpha.2" + s.version = "3.0.0.alpha.2.0" s.licenses = ["BSD"] s.summary = "Protocol Buffers" s.description = "Protocol Buffers are Google's data interchange format." -- cgit v1.2.3 From 7d8564f220de0132764793b42409403d9a9299fc Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Sat, 21 Feb 2015 13:55:43 -0800 Subject: Update version number to 3.0.0-alpha-2 Change-Id: Icecb25db34ae5e6d5142a2d75ca7216ba018abb2 --- configure.ac | 2 +- java/pom.xml | 4 ++-- javanano/pom.xml | 4 ++-- python/setup.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index b68468e4..59bf7577 100644 --- a/configure.ac +++ b/configure.ac @@ -12,7 +12,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.0.0-pre],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.0.0-alpha-2],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/java/pom.xml b/java/pom.xml index bbadc656..75d4c7f6 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf protobuf-java - 3.0.0-pre + 3.0.0-alpha-2 bundle Protocol Buffer Java API @@ -152,7 +152,7 @@ https://developers.google.com/protocol-buffers/ com.google.protobuf - com.google.protobuf;version=3.0.0-pre + com.google.protobuf;version=3.0.0-alpha-2 diff --git a/javanano/pom.xml b/javanano/pom.xml index 409d8d61..50056cd3 100644 --- a/javanano/pom.xml +++ b/javanano/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf.nano protobuf-javanano - 2.6.2-pre + 3.0.0-alpha-2 bundle Protocol Buffer JavaNano API @@ -156,7 +156,7 @@ https://developers.google.com/protocol-buffers/ com.google.protobuf - com.google.protobuf;version=2.6.2-pre + com.google.protobuf;version=3.0.0-alpha-2 diff --git a/python/setup.py b/python/setup.py index cfe25cc0..45dd0761 100755 --- a/python/setup.py +++ b/python/setup.py @@ -163,7 +163,7 @@ if __name__ == '__main__': )) setup(name = 'protobuf', - version = '3.0.0-pre', + version = '3.0.0-alpha-2', packages = [ 'google' ], namespace_packages = [ 'google' ], test_suite = 'setup.MakeTestSuite', -- cgit v1.2.3 From ff35de3ddd7ff844a72434c6cc76f3c84a852622 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Sat, 21 Feb 2015 14:58:02 -0800 Subject: Include Ruby and JavaNano into dist packages. Changes the automake to use tar-ustar for tarbal format, which supports filenames exceeding 99-chars. Otherwise Nano source files cannot be distributed. Change-Id: I33e43148e317374cd46417bebb8559e40fac7299 --- Makefile.am | 42 +++++++++++++++++++++++++++++++++++++++++- configure.ac | 2 +- post_process_dist.sh | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 95316eb5..1c64b710 100644 --- a/Makefile.am +++ b/Makefile.am @@ -154,6 +154,46 @@ java_EXTRA_DIST= \ java/pom.xml \ java/README.txt +javanano_EXTRA_DIST= \ + javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java \ + javanano/src/main/java/com/google/protobuf/nano/FieldData.java \ + javanano/src/main/java/com/google/protobuf/nano/FieldArray.java \ + javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java \ + javanano/src/main/java/com/google/protobuf/nano/Extension.java \ + javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java \ + javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java \ + javanano/src/main/java/com/google/protobuf/nano/MessageNano.java \ + javanano/src/main/java/com/google/protobuf/nano/InternalNano.java \ + javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java \ + javanano/src/main/java/com/google/protobuf/nano/MapFactories.java \ + javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java \ + javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java \ + javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/NanoTest.java \ + javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto \ + javanano/src/test/java/com/google/protobuf/nano/map_test.proto \ + javanano/README.txt \ + javanano/pom.xml + + python_EXTRA_DIST= \ python/google/protobuf/internal/api_implementation.cc \ python/google/protobuf/internal/api_implementation.py \ @@ -260,7 +300,7 @@ ruby_EXTRA_DIST= \ ruby/tests/generated_code.rb \ ruby/tests/generated_code_test.rb -all_EXTRA_DIST=$(java_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) +all_EXTRA_DIST=$(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST) \ autogen.sh \ diff --git a/configure.ac b/configure.ac index 59bf7577..b5eb9399 100644 --- a/configure.ac +++ b/configure.ac @@ -37,7 +37,7 @@ AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"], AC_CANONICAL_TARGET -AM_INIT_AUTOMAKE([subdir-objects]) +AM_INIT_AUTOMAKE([1.9 tar-ustar subdir-objects]) AC_ARG_WITH([zlib], [AS_HELP_STRING([--with-zlib], diff --git a/post_process_dist.sh b/post_process_dist.sh index 733fa088..3c01ed8f 100755 --- a/post_process_dist.sh +++ b/post_process_dist.sh @@ -27,7 +27,7 @@ fi set -ex -LANGUAGES="cpp java python" +LANGUAGES="cpp java javanano python ruby" BASENAME=`basename $1 .tar.gz` VERSION=${BASENAME:9} -- cgit v1.2.3 From 7a00a1e42495495cef8bc20821b9554c6afb3ab5 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Sat, 21 Feb 2015 17:28:51 -0800 Subject: Add shutdown code for several newly introduced leaks; Disable commandline interface test for heap check tests. Change-Id: I02aa2ad9704e3c70dcecae8b3b3557b18607d455 --- .../compiler/command_line_interface_unittest.cc | 6 ++++++ .../protobuf/generated_message_reflection.cc | 6 ++++++ src/google/protobuf/message.cc | 24 ++++++++++++++++++++++ src/google/protobuf/stubs/singleton.h | 6 +++++- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index dbaaa405..64e877a3 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -64,6 +64,10 @@ #include +// Disable the whole test when we use tcmalloc for "draconian" heap checks, in +// which case tcmalloc will print warnings that fail the plugin tests. +#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN + namespace google { namespace protobuf { namespace compiler { @@ -1663,3 +1667,5 @@ TEST_F(EncodeDecodeTest, ProtoParseError) { } // namespace compiler } // namespace protobuf } // namespace google + +#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index b500b9c5..34826801 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -247,8 +247,14 @@ namespace { UnknownFieldSet* empty_unknown_field_set_ = NULL; GOOGLE_PROTOBUF_DECLARE_ONCE(empty_unknown_field_set_once_); +void DeleteEmptyUnknownFieldSet() { + delete empty_unknown_field_set_; + empty_unknown_field_set_ = NULL; +} + void InitEmptyUnknownFieldSet() { empty_unknown_field_set_ = new UnknownFieldSet; + internal::OnShutdown(&DeleteEmptyUnknownFieldSet); } const UnknownFieldSet& GetEmptyUnknownFieldSet() { diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index afe95461..28955b35 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -440,6 +440,30 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( return NULL; } +namespace internal { +namespace { +void ShutdownRepeatedFieldAccessor() { + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton >::ShutDown(); + Singleton::ShutDown(); + Singleton::ShutDown(); + Singleton::ShutDown(); +}; + +struct ShutdownRepeatedFieldRegister { + ShutdownRepeatedFieldRegister() { + OnShutdown(&ShutdownRepeatedFieldAccessor); + } +} shutdown_; + +} // namesapce +} // namespace internal + namespace internal { // Macro defined in repeated_field.h. We can only define the Message-specific // GenericTypeHandler specializations here because we depend on Message, which diff --git a/src/google/protobuf/stubs/singleton.h b/src/google/protobuf/stubs/singleton.h index e123e4fe..9301f549 100644 --- a/src/google/protobuf/stubs/singleton.h +++ b/src/google/protobuf/stubs/singleton.h @@ -44,6 +44,10 @@ class Singleton { GoogleOnceInit(&once_, &Singleton::Init); return instance_; } + static void ShutDown() { + delete instance_; + instance_ = NULL; + } private: static void Init() { instance_ = new T(); @@ -56,7 +60,7 @@ template ProtobufOnceType Singleton::once_; template -T* Singleton::instance_; +T* Singleton::instance_ = NULL; } // namespace internal } // namespace protobuf } // namespace google -- cgit v1.2.3 From 5b033ae2f7381779e28e665b85304b6764899b70 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Sun, 22 Feb 2015 09:29:42 -0800 Subject: Add JavaNano and Ruby protoc files into vs proj Change-Id: I01f6543bb24c015181b9b7b82eb0ea3dc26f0ee3 --- vsprojects/extract_includes.bat | 4 + vsprojects/libprotoc.vcproj | 1054 ++++++++++++++++++++------------------- 2 files changed, 539 insertions(+), 519 deletions(-) diff --git a/vsprojects/extract_includes.bat b/vsprojects/extract_includes.bat index 587c1a8a..3f902e8e 100755 --- a/vsprojects/extract_includes.bat +++ b/vsprojects/extract_includes.bat @@ -6,7 +6,9 @@ md include\google\protobuf\io md include\google\protobuf\compiler md include\google\protobuf\compiler\cpp md include\google\protobuf\compiler\java +md include\google\protobuf\compiler\javanano md include\google\protobuf\compiler\python +md include\google\protobuf\compiler\ruby copy ..\src\google\protobuf\arena.h include\google\protobuf\arena.h copy ..\src\google\protobuf\arenastring.h include\google\protobuf\arenastring.h copy ..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h @@ -14,10 +16,12 @@ copy ..\src\google\protobuf\compiler\command_line_interface.h include\google\pro copy ..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h +copy ..\src\google\protobuf\compiler\javanano\javanano_generator.h include\google\protobuf\compiler\javanano\javanano_generator.h copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h copy ..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h copy ..\src\google\protobuf\compiler\plugin.pb.h include\google\protobuf\compiler\plugin.pb.h copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h +copy ..\src\google\protobuf\compiler\ruby\ruby_generator.h include\google\protobuf\compiler\ruby\ruby_generator.h copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h copy ..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h copy ..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj index 6b1e8864..455c2cc2 100644 --- a/vsprojects/libprotoc.vcproj +++ b/vsprojects/libprotoc.vcproj @@ -1,526 +1,542 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ProjectType="Visual C++" + Version="9.00" + Name="libprotoc" + ProjectGUID="{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}" + Keyword="Win32Proj" + TargetFrameworkVersion="0" + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 21fb217e6ae4c28e20f91b93d25f030f0bba237f Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 23 Feb 2015 12:27:52 -0800 Subject: Updated Ruby README with more details on getting started. Change-Id: I54df314660cdb861ad8c4da75a08d4cb97faf638 --- ruby/README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/ruby/README.md b/ruby/README.md index 59d5ace8..84f4a775 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -7,8 +7,51 @@ we recommend using protoc's Ruby generation support with .proto files. The build process in this directory only installs the extension; you need to install protoc as well to have Ruby code generation functionality. -Installation ------------- +Installation from Gem +--------------------- + +When we release a version of Protocol Buffers, we will upload a Gem to +[RubyGems](https://www.rubygems.org/). To use this pre-packaged gem, simply +install it as you would any other gem: + + $ gem install [--prerelease] google-protobuf + +The `--pre` flag is necessary if we have not yet made a non-alpha/beta release +of the Ruby extension; it allows `gem` to consider these "pre-release" +alpha/beta versions. + +Once the gem is installed, you may or may not need `protoc`. If you write your +message type descriptions directly in the Ruby DSL, you do not need it. +However, if you wish to generate the Ruby DSL from a `.proto` file, you will +also want to install Protocol Buffers itself, as described in this repository's +main `README` file. The version of `protoc` included in the latest release +supports the `--ruby_out` option to generate Ruby code. + +A simple example of using the Ruby extension follows. More extensive +documentation may be found in the RubyDoc comments (`call-seq` tags) in the +source, and we plan to release separate, more detailed, documentation at a +later date. + + require 'google/protobuf' + + # generated from my_proto_types.proto with protoc: + # $ protoc --ruby_out=. my_proto_types.proto + require 'my_proto_types' + + mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"]) + mymessage.field1 = 43 + mymessage.field2.push("d") + mymessage.field3 = SubMessage.new(:foo => 100) + + encoded_data = MyTestMessage.encode(mymessage) + decoded = MyTestMessage.decode(encoded_data) + assert decoded == mymessage + + puts "JSON:" + puts MyTestMessage.encode_json(mymessage) + +Installation from Source (Building Gem) +--------------------------------------- To build this Ruby extension, you will need: -- cgit v1.2.3 From 20042b72da0a4fef46fd90e1e7766d124f16e465 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Mon, 23 Feb 2015 15:56:38 -0800 Subject: Fix Java maps reflection to call onChange to populate changes to parent builders. Change-Id: Ibf6ae3c0fe6bc31f74b8018c81a5af461b1c24ea --- .../java/com/google/protobuf/GeneratedMessage.java | 50 +++--- .../src/test/java/com/google/protobuf/MapTest.java | 171 +++++++++++++-------- 2 files changed, 132 insertions(+), 89 deletions(-) diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index 156d1633..d8510cb5 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -73,7 +73,7 @@ public abstract class GeneratedMessage extends AbstractMessage /** For use by generated code only. */ protected UnknownFieldSet unknownFields; - + protected GeneratedMessage() { unknownFields = UnknownFieldSet.getDefaultInstance(); } @@ -549,12 +549,12 @@ public abstract class GeneratedMessage extends AbstractMessage * 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. + * directly and thus enables us to access the map field as a list. */ @SuppressWarnings({"unused", "rawtypes"}) protected MapField internalGetMapField(int fieldNumber) { @@ -683,7 +683,7 @@ public abstract class GeneratedMessage extends AbstractMessage public final Type getExtension( final ExtensionLite extensionLite) { Extension extension = checkNotLite(extensionLite); - + verifyExtensionContainingType(extension); FieldDescriptor descriptor = extension.getDescriptor(); final Object value = extensions.getField(descriptor); @@ -1313,7 +1313,7 @@ public abstract class GeneratedMessage extends AbstractMessage implements ExtensionDescriptorRetriever { private volatile FieldDescriptor descriptor; protected abstract FieldDescriptor loadDescriptor(); - + public FieldDescriptor getDescriptor() { if (descriptor == null) { synchronized (this) { @@ -1651,17 +1651,17 @@ public abstract class GeneratedMessage extends AbstractMessage } } } - + /** * 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. + * directly and thus enables us to access the map field as a list. */ @SuppressWarnings({"rawtypes", "unused"}) protected MapField internalGetMapField(int fieldNumber) { @@ -1709,7 +1709,7 @@ public abstract class GeneratedMessage extends AbstractMessage oneofs = new OneofAccessor[descriptor.getOneofs().size()]; initialized = false; } - + private boolean isMapFieldEnabled(FieldDescriptor field) { boolean result = true; return result; @@ -1934,11 +1934,11 @@ public abstract class GeneratedMessage extends AbstractMessage protected final FieldDescriptor field; protected final boolean isOneofField; protected final boolean hasHasMethod; - + private int getOneofFieldNumber(final GeneratedMessage message) { return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber(); } - + private int getOneofFieldNumber(final GeneratedMessage.Builder builder) { return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber(); } @@ -2130,15 +2130,15 @@ public abstract class GeneratedMessage extends AbstractMessage private final FieldDescriptor field; private final Message mapEntryMessageDefaultInstance; - + private MapField getMapField(GeneratedMessage message) { return (MapField) message.internalGetMapField(field.getNumber()); } - + private MapField getMapField(GeneratedMessage.Builder builder) { return (MapField) builder.internalGetMapField(field.getNumber()); } - + public Object get(GeneratedMessage message) { List result = new ArrayList(); for (int i = 0; i < getRepeatedCount(message); i++) { @@ -2171,10 +2171,12 @@ public abstract class GeneratedMessage extends AbstractMessage } public void setRepeated(Builder builder, int index, Object value) { + builder.onChanged(); getMapField(builder).getMutableList().set(index, (Message) value); } public void addRepeated(Builder builder, Object value) { + builder.onChanged(); getMapField(builder).getMutableList().add((Message) value); } @@ -2197,6 +2199,7 @@ public abstract class GeneratedMessage extends AbstractMessage } public void clear(Builder builder) { + builder.onChanged(); getMapField(builder).getMutableList().clear(); } @@ -2208,7 +2211,7 @@ public abstract class GeneratedMessage extends AbstractMessage throw new UnsupportedOperationException( "Nested builder not supported for map fields."); } - + public com.google.protobuf.Message.Builder getRepeatedBuilder( Builder builder, int index) { throw new UnsupportedOperationException( @@ -2226,7 +2229,7 @@ public abstract class GeneratedMessage extends AbstractMessage final Class builderClass, final String containingOneofCamelCaseName) { super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName); - + enumDescriptor = descriptor.getEnumType(); valueOfMethod = getMethodOrDie(type, "valueOf", @@ -2244,12 +2247,12 @@ public abstract class GeneratedMessage extends AbstractMessage 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; @@ -2291,7 +2294,7 @@ public abstract class GeneratedMessage extends AbstractMessage final Class messageClass, final Class builderClass) { super(descriptor, camelCaseName, messageClass, builderClass); - + enumDescriptor = descriptor.getEnumType(); valueOfMethod = getMethodOrDie(type, "valueOf", @@ -2315,7 +2318,7 @@ public abstract class GeneratedMessage extends AbstractMessage private final Method valueOfMethod; private final Method getValueDescriptorMethod; - + private boolean supportUnknownEnumValue; private Method getRepeatedValueMethod; private Method getRepeatedValueMethodBuilder; @@ -2395,7 +2398,8 @@ public abstract class GeneratedMessage extends AbstractMessage final Class messageClass, final Class builderClass, final String containingOneofCamelCaseName) { - super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName); + super(descriptor, camelCaseName, messageClass, builderClass, + containingOneofCamelCaseName); newBuilderMethod = getMethodOrDie(type, "newBuilder"); getBuilderMethodBuilder = @@ -2492,7 +2496,7 @@ public abstract class GeneratedMessage extends AbstractMessage 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}. @@ -2503,7 +2507,7 @@ public abstract class GeneratedMessage extends AbstractMessage if (extension.isLite()) { throw new IllegalArgumentException("Expected non-lite extension."); } - + return (Extension) extension; } } diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java index 9a25e302..6a1e9078 100644 --- a/java/src/test/java/com/google/protobuf/MapTest.java +++ b/java/src/test/java/com/google/protobuf/MapTest.java @@ -57,22 +57,22 @@ public class MapTest 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); @@ -88,22 +88,22 @@ public class MapTest extends TestCase { 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()); @@ -118,21 +118,21 @@ public class MapTest extends TestCase { 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); @@ -148,22 +148,22 @@ public class MapTest extends TestCase { 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()); @@ -183,17 +183,17 @@ public class MapTest extends TestCase { 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(); message = builder.build(); @@ -207,14 +207,14 @@ public class MapTest extends TestCase { 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(); @@ -222,12 +222,12 @@ public class MapTest extends TestCase { message = TestMap.PARSER.parseFrom(message.toByteString()); assertMapValuesCleared(message); } - + 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()); @@ -236,7 +236,7 @@ public class MapTest extends TestCase { 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(); @@ -244,23 +244,23 @@ public class MapTest extends TestCase { b1.getMutableInt32ToInt32Field().put(3, 4); b1.getMutableInt32ToInt32Field().put(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 m2 = b2.build(); - + assertEquals(m1, m2); assertEquals(m1.hashCode(), m2.hashCode()); - + // Make sure we did compare map fields. b2.getMutableInt32ToInt32Field().put(1, 0); m2 = b2.build(); assertFalse(m1.equals(m2)); // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed // to be different. - + // Regression test for b/18549190: if a map is a subset of the other map, // equals() should return false. b2.getMutableInt32ToInt32Field().remove(1); @@ -268,57 +268,96 @@ public class MapTest extends TestCase { assertFalse(m1.equals(m2)); assertFalse(m2.equals(m1)); } - - + + public void testNestedBuilderOnChangeEventPropagation() { TestOnChangeEventPropagation.Builder parent = TestOnChangeEventPropagation.newBuilder(); parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(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); - + // 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); parent.getOptionalMessageBuilder().mergeFrom(other.build()); - + // Should be able to observe the change. message = parent.build(); assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); - + // Make yet another change by clearing the nested builder. parent.getOptionalMessageBuilder().clear(); - + // Should be able to observe the change. message = parent.build(); assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size()); } - + + public void testNestedBuilderOnChangeEventPropagationReflection() { + FieldDescriptor intMapField = f("int32_to_int32_field"); + // Create an outer message builder with nested builder. + TestOnChangeEventPropagation.Builder parentBuilder = + TestOnChangeEventPropagation.newBuilder(); + TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder(); + + // Create a map entry message. + TestMap.Builder entryBuilder = TestMap.newBuilder(); + entryBuilder.getMutableInt32ToInt32Field().put(1, 1); + + // Put the entry into the nested builder. + testMapBuilder.addRepeatedField( + intMapField, entryBuilder.getRepeatedField(intMapField, 0)); + + // Should be able to observe the change. + TestOnChangeEventPropagation message = parentBuilder.build(); + assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size()); + + // Change the entry value. + entryBuilder.getMutableInt32ToInt32Field().put(1, 4); + testMapBuilder = parentBuilder.getOptionalMessageBuilder(); + testMapBuilder.setRepeatedField( + intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0)); + + // Should be able to observe the change. + message = parentBuilder.build(); + assertEquals(4, + message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); + + // Clear the nested builder. + testMapBuilder = parentBuilder.getOptionalMessageBuilder(); + testMapBuilder.clearField(intMapField); + + // Should be able to observe the change. + message = parentBuilder.build(); + assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size()); + } + // 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)) { @@ -337,7 +376,7 @@ public class MapTest extends TestCase { assertEquals(value, values.get(key)); } } - + private static Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); @@ -348,7 +387,7 @@ public class MapTest extends TestCase { entryBuilder.setField(valueField, value); return entryBuilder.build(); } - + private static void setMapValues(Message.Builder builder, String name, Map values) { List entryList = new ArrayList(); for (Map.Entry entry : values.entrySet()) { @@ -357,7 +396,7 @@ public class MapTest extends TestCase { FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); builder.setField(field, entryList); } - + private static Map mapForValues( KeyType key1, ValueType value1, KeyType key2, ValueType value2) { @@ -385,14 +424,14 @@ public class MapTest extends TestCase { 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)); @@ -405,7 +444,7 @@ public class MapTest extends TestCase { 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)); @@ -425,7 +464,7 @@ public class MapTest extends TestCase { 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); @@ -442,35 +481,35 @@ public class MapTest extends TestCase { assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); } - + public void testTextFormat() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); setMapValues(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); 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()); } - + public void testReflectionEqualsAndHashCode() throws Exception { // Test that generated equals() and hashCode() will disregard the order // of map entries when comparing/hashing map fields. @@ -479,22 +518,22 @@ public class MapTest extends TestCase { 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(); @@ -502,7 +541,7 @@ public class MapTest extends TestCase { // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed // to be different. } - + public void testUnknownEnumValues() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); builder.getMutableInt32ToEnumFieldValue().put(0, 0); @@ -517,7 +556,7 @@ public class MapTest extends TestCase { assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2)); assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); - + // Unknown enum values should be preserved after: // 1. Serialization and parsing. // 2. toBuild(). @@ -528,7 +567,7 @@ public class MapTest extends TestCase { assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); builder = TestMap.newBuilder().mergeFrom(message); assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); - + // hashCode()/equals() should take unknown enum values into account. builder.getMutableInt32ToEnumFieldValue().put(2, 1001); TestMap message2 = builder.build(); @@ -538,17 +577,17 @@ public class MapTest extends TestCase { // should be the same. assertTrue(message.getInt32ToEnumField().equals(message2.getInt32ToEnumField())); } - + public void testUnknownEnumValuesInReflectionApi() throws Exception { Descriptor descriptor = TestMap.getDescriptor(); EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor(); FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field"); - + Map data = new HashMap(); data.put(0, 0); data.put(1, 1); data.put(2, 1000); // unknown value. - + TestMap.Builder builder = TestMap.newBuilder(); for (Map.Entry entry : data.entrySet()) { builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue()); -- cgit v1.2.3 From e70329c6c0a2a9ebbbd1038f076d823e730512a7 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Mon, 23 Feb 2015 17:24:36 -0800 Subject: Propogate onChange() event when getFooBuilder() is on an oneof message field. Change-Id: Idb5b53da5accd24038a895aba49b684eeee95814 --- .../java/com/google/protobuf/GeneratedMessageTest.java | 14 +++++++++++++- src/google/protobuf/compiler/java/java_message_field.cc | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 41ed7bd0..2d101ba7 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -56,9 +56,10 @@ import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.ForeignEnum; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder; +import protobuf_unittest.UnittestProto.NestedTestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; -import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder; import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; import protobuf_unittest.UnittestProto.TestOneof2; @@ -1510,6 +1511,17 @@ public class GeneratedMessageTest extends TestCase { } } + public void testOneofNestedBuilderOnChangePropagation() { + NestedTestAllTypes.Builder parentBuilder = NestedTestAllTypes.newBuilder(); + TestAllTypes.Builder builder = parentBuilder.getPayloadBuilder(); + builder.getOneofNestedMessageBuilder(); + assertTrue(builder.hasOneofNestedMessage()); + assertTrue(parentBuilder.hasPayload()); + NestedTestAllTypes message = parentBuilder.build(); + assertTrue(message.hasPayload()); + assertTrue(message.getPayload().hasOneofNestedMessage()); + } + public void testGetRepeatedFieldBuilder() { Descriptor descriptor = TestAllTypes.getDescriptor(); diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index 538f1248..a2d12a38 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -718,6 +718,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " $oneof_name$_ = null;\n" " }\n" " $set_oneof_case_message$;\n" + " $on_changed$;\n" " return $name$Builder_;\n" "}\n"); } -- cgit v1.2.3