aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Adam Cozzette <acozzette@google.com>2016-06-29 15:23:27 -0700
committerGravatar Adam Cozzette <acozzette@google.com>2016-06-29 15:38:03 -0700
commitd64a2d9941c36a7bc2a7959ea10ab8363192ac14 (patch)
tree52330d146ad63d3d70f3baade00d5d1fea8f5e0c
parentc18aa7795a2e02ef700ff8b039d94ecdcc33432f (diff)
Integrated internal changes from Google
This includes all internal changes from around May 20 to now.
-rw-r--r--Makefile.am2
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessage.java95
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java46
-rw-r--r--java/core/src/main/java/com/google/protobuf/BooleanArrayList.java46
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedOutputStream.java113
-rw-r--r--java/core/src/main/java/com/google/protobuf/Descriptors.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/DoubleArrayList.java50
-rw-r--r--java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java11
-rw-r--r--java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java95
-rw-r--r--java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java57
-rw-r--r--java/core/src/main/java/com/google/protobuf/FieldSet.java26
-rw-r--r--java/core/src/main/java/com/google/protobuf/FloatArrayList.java51
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessage.java202
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java238
-rw-r--r--java/core/src/main/java/com/google/protobuf/IntArrayList.java51
-rw-r--r--java/core/src/main/java/com/google/protobuf/LongArrayList.java53
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntry.java219
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntryLite.java319
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapField.java413
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapFieldLite.java445
-rw-r--r--java/core/src/main/java/com/google/protobuf/MessageReflection.java3
-rw-r--r--java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java708
-rw-r--r--java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java241
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormat.java91
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java17
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnsafeUtil.java210
-rw-r--r--java/core/src/main/java/com/google/protobuf/Utf8.java248
-rw-r--r--java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java190
-rw-r--r--java/core/src/test/java/com/google/protobuf/DescriptorsTest.java8
-rw-r--r--java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java149
-rw-r--r--java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java245
-rw-r--r--java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java20
-rw-r--r--java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java149
-rw-r--r--java/core/src/test/java/com/google/protobuf/IntArrayListTest.java143
-rw-r--r--java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java17
-rw-r--r--java/core/src/test/java/com/google/protobuf/LiteTest.java31
-rw-r--r--java/core/src/test/java/com/google/protobuf/LongArrayListTest.java183
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java717
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapForProto2Test.java654
-rw-r--r--java/core/src/test/java/com/google/protobuf/MapTest.java588
-rw-r--r--java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java190
-rw-r--r--java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java155
-rw-r--r--java/core/src/test/java/com/google/protobuf/TestUtil.java5
-rw-r--r--java/core/src/test/java/com/google/protobuf/TextFormatTest.java7
-rw-r--r--java/core/src/test/proto/com/google/protobuf/field_presence_test.proto2
-rw-r--r--java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto11
-rw-r--r--java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto11
-rw-r--r--java/core/src/test/proto/com/google/protobuf/map_test.proto12
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/Durations.java256
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java48
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java78
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/JsonFormat.java715
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/TimeUtil.java381
-rw-r--r--java/util/src/main/java/com/google/protobuf/util/Timestamps.java349
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java113
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java733
-rw-r--r--java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java77
-rw-r--r--java/util/src/test/proto/com/google/protobuf/util/json_test.proto1
-rw-r--r--js/binary/constants.js4
-rw-r--r--js/binary/decoder_test.js3
-rw-r--r--js/binary/reader_test.js25
-rw-r--r--js/binary/writer.js36
-rw-r--r--js/message.js97
-rw-r--r--js/message_test.js33
-rw-r--r--js/test.proto1
-rw-r--r--js/testbinary.proto29
-rwxr-xr-xpython/google/protobuf/descriptor.py42
-rw-r--r--python/google/protobuf/descriptor_pool.py65
-rwxr-xr-xpython/google/protobuf/internal/containers.py6
-rw-r--r--python/google/protobuf/internal/descriptor_pool_test.py18
-rwxr-xr-xpython/google/protobuf/internal/descriptor_test.py41
-rw-r--r--python/google/protobuf/internal/file_options_test.proto43
-rw-r--r--python/google/protobuf/internal/json_format_test.py13
-rwxr-xr-xpython/google/protobuf/internal/message_test.py4
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py624
-rw-r--r--python/google/protobuf/json_format.py762
-rw-r--r--python/google/protobuf/pyext/descriptor.cc277
-rw-r--r--python/google/protobuf/pyext/descriptor.h6
-rw-r--r--python/google/protobuf/pyext/descriptor_containers.cc158
-rw-r--r--python/google/protobuf/pyext/descriptor_containers.h8
-rw-r--r--python/google/protobuf/pyext/descriptor_pool.cc38
-rw-r--r--python/google/protobuf/pyext/map_container.cc1
-rw-r--r--python/google/protobuf/pyext/message.cc66
-rw-r--r--python/google/protobuf/pyext/message.h6
-rw-r--r--python/google/protobuf/pyext/message_module.cc88
-rwxr-xr-xpython/google/protobuf/text_format.py613
-rwxr-xr-xpython/setup.py2
-rw-r--r--src/google/protobuf/any.pb.cc4
-rw-r--r--src/google/protobuf/any.pb.h8
-rw-r--r--src/google/protobuf/any.proto16
-rw-r--r--src/google/protobuf/api.pb.cc32
-rw-r--r--src/google/protobuf/api.pb.h24
-rwxr-xr-xsrc/google/protobuf/arena.cc11
-rw-r--r--src/google/protobuf/arena.h2
-rw-r--r--src/google/protobuf/arena_unittest.cc1
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc27
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc57
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc39
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_options.h2
-rw-r--r--src/google/protobuf/compiler/java/java_context.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_context.h14
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_enum.h5
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc29
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field_lite.cc10
-rw-r--r--src/google/protobuf/compiler/java/java_enum_lite.cc17
-rw-r--r--src/google/protobuf/compiler/java/java_enum_lite.h5
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc87
-rw-r--r--src/google/protobuf/compiler/java/java_file.h11
-rw-r--r--src/google/protobuf/compiler/java/java_generator.cc87
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.cc23
-rw-r--r--src/google/protobuf/compiler/java/java_helpers.h54
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field.cc12
-rw-r--r--src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc57
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.cc396
-rw-r--r--src/google/protobuf/compiler/java/java_map_field.h1
-rw-r--r--src/google/protobuf/compiler/java/java_map_field_lite.cc502
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc56
-rw-r--r--src/google/protobuf/compiler/java/java_message.h3
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc35
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.cc35
-rw-r--r--src/google/protobuf/compiler/java/java_message_lite.h3
-rw-r--r--src/google/protobuf/compiler/java/java_options.h73
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc4
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field_lite.cc38
-rw-r--r--src/google/protobuf/compiler/java/java_service.cc5
-rw-r--r--src/google/protobuf/compiler/java/java_service.h4
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.cc50
-rw-r--r--src/google/protobuf/compiler/java/java_shared_code_generator.h13
-rw-r--r--src/google/protobuf/compiler/java/java_string_field.cc8
-rwxr-xr-xsrc/google/protobuf/compiler/js/js_generator.cc405
-rw-r--r--src/google/protobuf/compiler/main.cc8
-rw-r--r--src/google/protobuf/compiler/parser.cc10
-rw-r--r--src/google/protobuf/compiler/plugin.pb.cc20
-rw-r--r--src/google/protobuf/compiler/plugin.pb.h24
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc25
-rw-r--r--src/google/protobuf/compiler/python/python_generator.h2
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc20
-rw-r--r--src/google/protobuf/descriptor.cc21
-rw-r--r--src/google/protobuf/descriptor.h9
-rw-r--r--src/google/protobuf/descriptor.pb.cc861
-rw-r--r--src/google/protobuf/descriptor.pb.h384
-rw-r--r--src/google/protobuf/descriptor.proto9
-rw-r--r--src/google/protobuf/descriptor_database_unittest.cc1
-rw-r--r--src/google/protobuf/descriptor_unittest.cc10
-rw-r--r--src/google/protobuf/duration.pb.cc4
-rw-r--r--src/google/protobuf/duration.pb.h8
-rw-r--r--src/google/protobuf/dynamic_message.cc1
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc3
-rw-r--r--src/google/protobuf/empty.pb.cc4
-rw-r--r--src/google/protobuf/empty.pb.h8
-rw-r--r--src/google/protobuf/extension_set.cc71
-rw-r--r--src/google/protobuf/extension_set.h71
-rw-r--r--src/google/protobuf/extension_set_heavy.cc85
-rw-r--r--src/google/protobuf/extension_set_unittest.cc68
-rw-r--r--src/google/protobuf/field_mask.pb.cc4
-rw-r--r--src/google/protobuf/field_mask.pb.h8
-rw-r--r--src/google/protobuf/field_mask.proto52
-rw-r--r--src/google/protobuf/generated_message_reflection.cc3
-rw-r--r--src/google/protobuf/generated_message_reflection_unittest.cc67
-rw-r--r--src/google/protobuf/io/coded_stream.cc117
-rw-r--r--src/google/protobuf/io/coded_stream.h26
-rw-r--r--src/google/protobuf/io/printer.h20
-rw-r--r--src/google/protobuf/io/zero_copy_stream_impl_lite.h1
-rw-r--r--src/google/protobuf/map.h20
-rw-r--r--src/google/protobuf/map_entry.h6
-rw-r--r--src/google/protobuf/map_entry_lite.h147
-rw-r--r--src/google/protobuf/map_field_test.cc2
-rw-r--r--src/google/protobuf/map_test.cc204
-rw-r--r--src/google/protobuf/map_type_handler.h42
-rw-r--r--src/google/protobuf/message.h4
-rw-r--r--src/google/protobuf/message_lite.cc3
-rw-r--r--src/google/protobuf/message_lite.h27
-rw-r--r--src/google/protobuf/repeated_field.h30
-rw-r--r--src/google/protobuf/source_context.pb.cc4
-rw-r--r--src/google/protobuf/source_context.pb.h8
-rw-r--r--src/google/protobuf/source_context.proto2
-rw-r--r--src/google/protobuf/struct.pb.cc41
-rw-r--r--src/google/protobuf/struct.pb.h24
-rw-r--r--src/google/protobuf/stubs/mathlimits.h6
-rw-r--r--src/google/protobuf/stubs/port.h9
-rw-r--r--src/google/protobuf/test_util.cc6
-rw-r--r--src/google/protobuf/testing/googletest.cc4
-rw-r--r--src/google/protobuf/text_format.cc54
-rw-r--r--src/google/protobuf/text_format_unittest.cc75
-rw-r--r--src/google/protobuf/timestamp.pb.cc4
-rw-r--r--src/google/protobuf/timestamp.pb.h8
-rw-r--r--src/google/protobuf/type.pb.cc56
-rw-r--r--src/google/protobuf/type.pb.h40
-rw-r--r--src/google/protobuf/unittest.proto1
-rw-r--r--src/google/protobuf/unittest_custom_options.proto9
-rw-r--r--src/google/protobuf/util/field_mask_util.cc54
-rw-r--r--src/google/protobuf/util/field_mask_util.h12
-rw-r--r--src/google/protobuf/util/field_mask_util_test.cc115
-rw-r--r--src/google/protobuf/util/internal/datapiece.cc30
-rw-r--r--src/google/protobuf/util/internal/datapiece.h10
-rw-r--r--src/google/protobuf/util/internal/json_escaping.cc2
-rw-r--r--src/google/protobuf/util/internal/object_writer.h1
-rw-r--r--src/google/protobuf/util/internal/proto_writer.cc30
-rw-r--r--src/google/protobuf/util/internal/proto_writer.h4
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.cc12
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.h4
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.cc9
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.h12
-rw-r--r--src/google/protobuf/util/internal/utility.cc10
-rw-r--r--src/google/protobuf/util/internal/utility.h4
-rw-r--r--src/google/protobuf/util/json_format_proto3.proto5
-rw-r--r--src/google/protobuf/util/message_differencer.cc3
-rw-r--r--src/google/protobuf/util/message_differencer.h6
-rw-r--r--src/google/protobuf/wire_format_lite.h40
-rw-r--r--src/google/protobuf/wire_format_lite_inl.h46
-rw-r--r--src/google/protobuf/wrappers.pb.cc36
-rw-r--r--src/google/protobuf/wrappers.pb.h72
216 files changed, 13676 insertions, 5406 deletions
diff --git a/Makefile.am b/Makefile.am
index 31ca9a14..1443b753 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -209,6 +209,7 @@ java_EXTRA_DIST=
java/core/src/main/java/com/google/protobuf/Extension.java \
java/core/src/main/java/com/google/protobuf/ExtensionLite.java \
java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java \
+ java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java \
java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
java/core/src/main/java/com/google/protobuf/FieldSet.java \
java/core/src/main/java/com/google/protobuf/FloatArrayList.java \
@@ -273,6 +274,7 @@ java_EXTRA_DIST=
java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java \
java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java \
java/core/src/test/java/com/google/protobuf/EnumTest.java \
+ java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java \
java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java \
java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java \
java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java \
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 03c0d579..b8fdb2b2 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -54,12 +54,40 @@ 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() {
@@ -460,6 +488,31 @@ public abstract class AbstractMessage
MessageReflection.findMissingFields(message));
}
+ /**
+ * Used to support nested builders and called to mark this builder as clean.
+ * Clean builders will propagate the {@link BuildParent#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 overriden 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 overriden by subclasses.");
+ }
+
// ===============================================================
// The following definitions seem to be required in order to make javac
// not produce weird errors like:
@@ -550,4 +603,44 @@ public abstract class AbstractMessage
return super.mergeDelimitedFrom(input, extensionRegistry);
}
}
+
+ /**
+ * @deprecated from v3.0.0-beta-3+, for compatiblity 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 compatiblity 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 compatiblity 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 compatiblity 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 43736dd1..046030f3 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -45,10 +45,10 @@ import java.util.Collection;
*/
public abstract class AbstractMessageLite<
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
- BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
+ BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
implements MessageLite {
protected int memoizedHashCode = 0;
-
+
@Override
public ByteString toByteString() {
try {
@@ -57,9 +57,7 @@ public abstract class AbstractMessageLite<
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);
}
}
@@ -72,9 +70,7 @@ public abstract class AbstractMessageLite<
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);
}
}
@@ -109,6 +105,11 @@ public abstract class AbstractMessageLite<
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()) {
@@ -120,7 +121,7 @@ public abstract class AbstractMessageLite<
final Collection<? super T> list) {
Builder.addAll(values, list);
}
-
+
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
@@ -156,9 +157,7 @@ public abstract class AbstractMessageLite<
} 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);
}
}
@@ -174,9 +173,7 @@ public abstract class AbstractMessageLite<
} 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);
}
}
@@ -197,9 +194,7 @@ public abstract class AbstractMessageLite<
} 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);
}
}
@@ -225,9 +220,7 @@ public abstract class AbstractMessageLite<
} 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);
}
}
@@ -321,7 +314,7 @@ public abstract class AbstractMessageLite<
return mergeDelimitedFrom(input,
ExtensionRegistryLite.getEmptyRegistry());
}
-
+
@Override
@SuppressWarnings("unchecked") // isInstance takes care of this
public BuilderType mergeFrom(final MessageLite other) {
@@ -329,12 +322,17 @@ public abstract class AbstractMessageLite<
throw new IllegalArgumentException(
"mergeFrom(MessageLite) can only merge messages of the same type.");
}
-
+
return internalMergeFrom((MessageType) other);
}
-
+
protected abstract BuilderType internalMergeFrom(MessageType message);
+ private String getReadingExceptionMessage(String target) {
+ return "Reading " + getClass().getName() + " from a " + target
+ + " threw an IOException (should never happen).";
+ }
+
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
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 8b2820b6..0d9f87ba 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -38,21 +38,22 @@ 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 {
-
+ extends AbstractProtobufList<Boolean>
+ implements BooleanList, RandomAccess {
+
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.
*/
@@ -72,13 +73,14 @@ final class BooleanArrayList
}
/**
- * Constructs a new mutable {@code BooleanArrayList}.
+ * Constructs a new mutable {@code BooleanArrayList}
+ * containing the same elements as {@code other}.
*/
- private BooleanArrayList(boolean[] array, int size) {
- this.array = array;
+ private BooleanArrayList(boolean[] other, int size) {
+ array = other;
this.size = size;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -91,14 +93,14 @@ final class BooleanArrayList
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;
}
@@ -170,7 +172,7 @@ final class BooleanArrayList
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);
@@ -178,10 +180,10 @@ final class BooleanArrayList
// 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;
@@ -195,38 +197,38 @@ final class BooleanArrayList
@Override
public boolean addAll(Collection<? extends Boolean> collection) {
ensureIsMutable();
-
+
if (collection == null) {
throw new NullPointerException();
}
-
+
// 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();
@@ -255,7 +257,7 @@ final class BooleanArrayList
/**
* 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/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index ad174d0f..576a350f 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -36,12 +36,9 @@ import com.google.protobuf.Utf8.UnpairedSurrogateException;
import java.io.IOException;
import java.io.OutputStream;
-import java.lang.reflect.Field;
import java.nio.BufferOverflowException;
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;
@@ -59,9 +56,8 @@ import java.util.logging.Logger;
*/
public abstract class CodedOutputStream extends ByteOutput {
private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
- private static final sun.misc.Unsafe UNSAFE = getUnsafe();
- private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
- private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+ private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
+ private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
private static final int FIXED_32_SIZE = 4;
private static final int FIXED_64_SIZE = 8;
@@ -869,7 +865,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeLengthDelimitedFieldSize(value.getSerializedSize());
}
- private static int computeLengthDelimitedFieldSize(int fieldLength) {
+ static int computeLengthDelimitedFieldSize(int fieldLength) {
return computeUInt32SizeNoTag(fieldLength) + fieldLength;
}
@@ -948,6 +944,10 @@ public abstract class CodedOutputStream extends ByteOutput {
OutOfSpaceException(Throwable cause) {
super(MESSAGE, cause);
}
+
+ OutOfSpaceException(String explanationMessage, Throwable cause) {
+ super(MESSAGE + ": " + explanationMessage, cause);
+ }
}
/**
@@ -1250,8 +1250,8 @@ public abstract class CodedOutputStream extends ByteOutput {
try {
buffer[position++] = value;
} catch (IndexOutOfBoundsException e) {
- throw new OutOfSpaceException(new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ throw new OutOfSpaceException(
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
}
}
@@ -1271,11 +1271,11 @@ public abstract class CodedOutputStream extends ByteOutput {
long pos = ARRAY_BASE_OFFSET + position;
while (true) {
if ((value & ~0x7F) == 0) {
- UNSAFE.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, pos++, (byte) value);
position++;
return;
} else {
- UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
position++;
value >>>= 7;
}
@@ -1293,8 +1293,7 @@ public abstract class CodedOutputStream extends ByteOutput {
}
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
}
}
}
@@ -1308,8 +1307,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) ((value >> 24) & 0xFF);
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
}
}
@@ -1319,11 +1317,11 @@ public abstract class CodedOutputStream extends ByteOutput {
long pos = ARRAY_BASE_OFFSET + position;
while (true) {
if ((value & ~0x7FL) == 0) {
- UNSAFE.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, pos++, (byte) value);
position++;
return;
} else {
- UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
position++;
value >>>= 7;
}
@@ -1341,8 +1339,7 @@ public abstract class CodedOutputStream extends ByteOutput {
}
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
}
}
}
@@ -1360,8 +1357,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
}
}
@@ -1372,8 +1368,7 @@ public abstract class CodedOutputStream extends ByteOutput {
position += length;
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
}
}
@@ -1390,8 +1385,7 @@ public abstract class CodedOutputStream extends ByteOutput {
position += length;
} catch (IndexOutOfBoundsException e) {
throw new OutOfSpaceException(
- new IndexOutOfBoundsException(
- String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+ String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
}
}
@@ -1855,10 +1849,10 @@ public abstract class CodedOutputStream extends ByteOutput {
long pos = originalPos;
while (true) {
if ((value & ~0x7F) == 0) {
- UNSAFE.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, pos++, (byte) value);
break;
} else {
- UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7;
}
}
@@ -1890,10 +1884,10 @@ public abstract class CodedOutputStream extends ByteOutput {
long pos = originalPos;
while (true) {
if ((value & ~0x7FL) == 0) {
- UNSAFE.putByte(buffer, pos++, (byte) value);
+ UnsafeUtil.putByte(buffer, pos++, (byte) value);
break;
} else {
- UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+ UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7;
}
}
@@ -2600,65 +2594,4 @@ public abstract class CodedOutputStream extends ByteOutput {
position = 0;
}
}
-
- /**
- * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
- * platform.
- */
- private 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.
- }
-
- logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
- unsafe != null ? "available" : "unavailable");
- return unsafe;
- }
-
- /**
- * Indicates whether or not unsafe array operations are supported on this platform.
- */
- // TODO(nathanmittler): Add support for Android's MemoryBlock.
- private static boolean supportsUnsafeArrayOperations() {
- boolean supported = false;
- if (UNSAFE != null) {
- try {
- UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
- UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
- supported = true;
- } catch (Throwable e) {
- // Do nothing.
- }
- }
- logger.log(Level.FINEST, "Unsafe array operations: {}",
- supported ? "available" : "unavailable");
- return supported;
- }
-
- /**
- * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
- * available.
- */
- private static <T> int byteArrayBaseOffset() {
- return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
- }
}
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 e00ea342..1c34c24f 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -871,6 +871,10 @@ public final class Descriptors {
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));
}
@@ -2513,6 +2517,10 @@ public final class Descriptors {
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));
@@ -2522,6 +2530,10 @@ public final class Descriptors {
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/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index a9543b83..6177f3ca 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -38,26 +38,27 @@ 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 {
-
+ extends AbstractProtobufList<Double>
+ implements DoubleList, RandomAccess {
+
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.
@@ -72,13 +73,14 @@ final class DoubleArrayList
}
/**
- * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
+ * Constructs a new mutable {@code DoubleArrayList}
+ * containing the same elements as {@code other}.
*/
- private DoubleArrayList(double[] array, int size) {
- this.array = array;
+ private DoubleArrayList(double[] other, int size) {
+ array = other;
this.size = size;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -91,14 +93,14 @@ final class DoubleArrayList
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;
}
@@ -119,7 +121,7 @@ final class DoubleArrayList
}
return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
}
-
+
@Override
public Double get(int index) {
return getDouble(index);
@@ -171,7 +173,7 @@ final class DoubleArrayList
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);
@@ -179,10 +181,10 @@ final class DoubleArrayList
// 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;
@@ -196,38 +198,38 @@ final class DoubleArrayList
@Override
public boolean addAll(Collection<? extends Double> collection) {
ensureIsMutable();
-
+
if (collection == null) {
throw new NullPointerException();
}
-
+
// 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();
@@ -256,7 +258,7 @@ final class DoubleArrayList
/**
* 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/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
index 0067392f..1c2e7e6f 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -101,7 +101,7 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistry getEmptyRegistry() {
- return EMPTY;
+ return EMPTY_REGISTRY;
}
@@ -243,6 +243,11 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
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 +316,7 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
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 +326,7 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
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 00000000..23174e24
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
@@ -0,0 +1,95 @@
+// 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
+ .getMethod(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 65cf7385..5e4d7739 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 @@ public class ExtensionRegistryLite {
// 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,14 +103,22 @@ public class ExtensionRegistryLite {
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. */
@@ -128,6 +152,23 @@ public class ExtensionRegistryLite {
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 +180,11 @@ public class ExtensionRegistryLite {
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 +196,9 @@ public class ExtensionRegistryLite {
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 4e89709f..5b251743 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -120,21 +120,21 @@ final class FieldSet<FieldDescriptorType extends
public boolean isImmutable() {
return isImmutable;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
-
+
if (!(o instanceof FieldSet)) {
return false;
}
-
+
FieldSet<?> other = (FieldSet<?>) o;
- return other.fields.equals(other.fields);
+ return fields.equals(other.fields);
}
-
+
@Override
public int hashCode() {
return fields.hashCode();
@@ -493,7 +493,7 @@ final class FieldSet<FieldDescriptorType extends
}
/**
- * 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) {
@@ -638,10 +638,11 @@ final class FieldSet<FieldDescriptorType extends
* {@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) {
@@ -804,9 +805,8 @@ final class FieldSet<FieldDescriptorType extends
* {@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 63cb6d77..90d6154b 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -38,25 +38,27 @@ 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 {
-
+final class FloatArrayList
+ extends AbstractProtobufList<Float>
+ implements FloatList, RandomAccess {
+
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.
@@ -71,13 +73,14 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
}
/**
- * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
+ * Constructs a new mutable {@code FloatArrayList}
+ * containing the same elements as {@code other}.
*/
- private FloatArrayList(float[] array, int size) {
- this.array = array;
+ private FloatArrayList(float[] other, int size) {
+ array = other;
this.size = size;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -90,14 +93,14 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
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;
}
@@ -117,7 +120,7 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
}
return new FloatArrayList(Arrays.copyOf(array, capacity), size);
}
-
+
@Override
public Float get(int index) {
return getFloat(index);
@@ -169,7 +172,7 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
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);
@@ -177,10 +180,10 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
// 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;
@@ -194,38 +197,38 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
@Override
public boolean addAll(Collection<? extends Float> collection) {
ensureIsMutable();
-
+
if (collection == null) {
throw new NullPointerException();
}
-
+
// 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();
@@ -254,7 +257,7 @@ final class FloatArrayList extends AbstractProtobufList<Float> implements FloatL
/**
* 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 790cb622..2c87302b 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -355,31 +355,30 @@ public abstract class GeneratedMessage extends AbstractMessage
// 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<BuilderType>>
extends AbstractMessage.Builder<BuilderType> {
@@ -403,6 +402,7 @@ public abstract class GeneratedMessage extends AbstractMessage
this.builderParent = builderParent;
}
+ @Override
void dispose() {
builderParent = null;
}
@@ -420,6 +420,7 @@ public abstract class GeneratedMessage extends AbstractMessage
* 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;
}
@@ -755,6 +756,33 @@ public abstract class GeneratedMessage extends AbstractMessage
<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);
}
/**
@@ -881,6 +909,53 @@ public abstract class GeneratedMessage extends AbstractMessage
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();
@@ -1269,6 +1344,95 @@ public abstract class GeneratedMessage extends AbstractMessage
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 final <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 final <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 final <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 final <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();
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 c5adc5ad..214971b1 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -59,15 +59,15 @@ import java.util.Map;
*/
public abstract class GeneratedMessageLite<
MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
- BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
+ BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
extends AbstractMessageLite<MessageType, BuilderType> {
/** For use by generated code only. Lazily initialized to reduce allocations. */
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() {
@@ -113,7 +113,7 @@ public abstract class GeneratedMessageLite<
}
return memoizedHashCode;
}
-
+
@SuppressWarnings("unchecked") // Guaranteed by runtime
int hashCode(HashCodeVisitor visitor) {
if (memoizedHashCode == 0) {
@@ -125,18 +125,18 @@ public abstract class GeneratedMessageLite<
}
return memoizedHashCode;
}
-
+
@SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
-
+
if (!getDefaultInstanceForType().getClass().isInstance(other)) {
return false;
}
-
+
try {
visit(EqualsVisitor.INSTANCE, (MessageType) other);
} catch (NotEqualsException e) {
@@ -144,7 +144,7 @@ public abstract class GeneratedMessageLite<
}
return true;
}
-
+
/**
* Same as {@link #equals(Object)} but throws {@code NotEqualsException}.
*/
@@ -153,7 +153,7 @@ public abstract class GeneratedMessageLite<
if (this == other) {
return true;
}
-
+
if (!getDefaultInstanceForType().getClass().isInstance(other)) {
return false;
}
@@ -161,7 +161,7 @@ public abstract class GeneratedMessageLite<
visit(visitor, (MessageType) other);
return true;
}
-
+
// 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.
@@ -174,10 +174,10 @@ public abstract class GeneratedMessageLite<
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 {
@@ -185,7 +185,7 @@ public abstract class GeneratedMessageLite<
if (WireFormat.getTagWireType(tag) == WireFormat.WIRETYPE_END_GROUP) {
return false;
}
-
+
ensureUnknownFieldsInitialized();
return unknownFields.mergeFieldFrom(tag, input);
}
@@ -197,7 +197,7 @@ public abstract class GeneratedMessageLite<
ensureUnknownFieldsInitialized();
unknownFields.mergeVarintField(tag, value);
}
-
+
/**
* Called by subclasses to parse an unknown field. For use by generated code only.
*/
@@ -205,7 +205,7 @@ public abstract class GeneratedMessageLite<
ensureUnknownFieldsInitialized();
unknownFields.mergeLengthDelimitedField(fieldNumber, value);
}
-
+
/**
* Called by subclasses to complete parsing. For use by generated code only.
*/
@@ -292,7 +292,7 @@ public abstract class GeneratedMessageLite<
dynamicMethod(MethodToInvoke.VISIT, visitor, other);
unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
}
-
+
/**
* Merge some unknown fields into the {@link UnknownFieldSetLite} for this
* message.
@@ -359,9 +359,9 @@ public abstract class GeneratedMessageLite<
if (isBuilt) {
return instance;
}
-
+
instance.makeImmutable();
-
+
isBuilt = true;
return instance;
}
@@ -374,24 +374,24 @@ public abstract class GeneratedMessageLite<
}
return result;
}
-
+
@Override
protected BuilderType internalMergeFrom(MessageType message) {
return mergeFrom(message);
}
-
+
/** All subclasses implement this. */
public BuilderType mergeFrom(MessageType message) {
copyOnWrite();
instance.visit(MergeFromVisitor.INSTANCE, message);
return (BuilderType) this;
}
-
+
@Override
public MessageType getDefaultInstanceForType() {
return defaultInstance;
}
-
+
@Override
public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
@@ -466,12 +466,12 @@ public abstract class GeneratedMessageLite<
super.visit(visitor, other);
extensions = visitor.visitExtensions(extensions, other.extensions);
}
-
+
/**
* 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(
@@ -590,7 +590,7 @@ public abstract class GeneratedMessageLite<
return true;
}
-
+
private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
@@ -607,7 +607,7 @@ public abstract class GeneratedMessageLite<
public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
GeneratedExtension<MessageType, Type> extensionLite =
checkIsLite(extension);
-
+
verifyExtensionContainingType(extensionLite);
return extensions.hasField(extensionLite.descriptor);
}
@@ -618,7 +618,7 @@ public abstract class GeneratedMessageLite<
final ExtensionLite<MessageType, List<Type>> extension) {
GeneratedExtension<MessageType, List<Type>> extensionLite =
checkIsLite(extension);
-
+
verifyExtensionContainingType(extensionLite);
return extensions.getRepeatedFieldCount(extensionLite.descriptor);
}
@@ -629,7 +629,7 @@ public abstract class GeneratedMessageLite<
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) {
@@ -660,7 +660,7 @@ public abstract class GeneratedMessageLite<
@Override
protected final void makeImmutable() {
super.makeImmutable();
-
+
extensions.makeImmutable();
}
@@ -734,7 +734,7 @@ public abstract class GeneratedMessageLite<
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
@@ -753,7 +753,7 @@ public abstract class GeneratedMessageLite<
if (!isBuilt) {
return;
}
-
+
super.copyOnWrite();
instance.extensions = instance.extensions.clone();
}
@@ -814,14 +814,14 @@ public abstract class GeneratedMessageLite<
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));
@@ -834,7 +834,7 @@ public abstract class GeneratedMessageLite<
final int index, final Type value) {
GeneratedExtension<MessageType, List<Type>> extensionLite =
checkIsLite(extension);
-
+
verifyExtensionContainingType(extensionLite);
copyOnWrite();
instance.extensions.setRepeatedField(
@@ -848,7 +848,7 @@ public abstract class GeneratedMessageLite<
final Type value) {
GeneratedExtension<MessageType, List<Type>> extensionLite =
checkIsLite(extension);
-
+
verifyExtensionContainingType(extensionLite);
copyOnWrite();
instance.extensions.addRepeatedField(
@@ -860,7 +860,7 @@ public abstract class GeneratedMessageLite<
public final <Type> BuilderType clearExtension(
final ExtensionLite<MessageType, ?> extension) {
GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
-
+
verifyExtensionContainingType(extensionLite);
copyOnWrite();
instance.extensions.clearField(extensionLite.descriptor);
@@ -1157,7 +1157,7 @@ public abstract class GeneratedMessageLite<
public static SerializedForm of(MessageLite message) {
return new SerializedForm(message);
}
-
+
private static final long serialVersionUID = 0L;
private final String messageClassName;
@@ -1191,7 +1191,7 @@ public abstract class GeneratedMessageLite<
} 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) {
@@ -1200,8 +1200,35 @@ public abstract class GeneratedMessageLite<
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);
+ }
+ }
}
-
+
/**
* Checks that the {@link Extension} is Lite and returns it as a
* {@link GeneratedExtension}.
@@ -1215,7 +1242,7 @@ public abstract class GeneratedMessageLite<
if (!extension.isLite()) {
throw new IllegalArgumentException("Expected a lite extension.");
}
-
+
return (GeneratedExtension<MessageType, T>) extension;
}
@@ -1227,8 +1254,8 @@ public abstract class GeneratedMessageLite<
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);
}
@@ -1246,7 +1273,7 @@ public abstract class GeneratedMessageLite<
protected static LongList emptyLongList() {
return LongArrayList.emptyList();
}
-
+
protected static LongList mutableCopy(LongList list) {
int size = list.size();
return list.mutableCopyWithCapacity(
@@ -1256,7 +1283,7 @@ public abstract class GeneratedMessageLite<
protected static FloatList emptyFloatList() {
return FloatArrayList.emptyList();
}
-
+
protected static FloatList mutableCopy(FloatList list) {
int size = list.size();
return list.mutableCopyWithCapacity(
@@ -1266,7 +1293,7 @@ public abstract class GeneratedMessageLite<
protected static DoubleList emptyDoubleList() {
return DoubleArrayList.emptyList();
}
-
+
protected static DoubleList mutableCopy(DoubleList list) {
int size = list.size();
return list.mutableCopyWithCapacity(
@@ -1276,7 +1303,7 @@ public abstract class GeneratedMessageLite<
protected static BooleanList emptyBooleanList() {
return BooleanArrayList.emptyList();
}
-
+
protected static BooleanList mutableCopy(BooleanList list) {
int size = list.size();
return list.mutableCopyWithCapacity(
@@ -1286,7 +1313,7 @@ public abstract class GeneratedMessageLite<
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(
@@ -1300,20 +1327,20 @@ public abstract class GeneratedMessageLite<
*/
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);
}
}
-
+
/**
* A static helper method for parsing a partial from input using the extension registry and the
* instance.
@@ -1335,14 +1362,14 @@ public abstract class GeneratedMessageLite<
}
return result;
}
-
+
protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T defaultInstance,
CodedInputStream input)
throws InvalidProtocolBufferException {
return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
}
-
+
/**
* Helper method to check if message is initialized.
*
@@ -1373,7 +1400,7 @@ public abstract class GeneratedMessageLite<
throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
}
-
+
// 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(
@@ -1393,7 +1420,7 @@ public abstract class GeneratedMessageLite<
throw e;
}
}
-
+
// 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(
@@ -1477,7 +1504,7 @@ public abstract class GeneratedMessageLite<
return checkMessageInitialized(
parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry));
}
-
+
private static <T extends GeneratedMessageLite<T, ?>> T parsePartialDelimitedFrom(
T defaultInstance,
InputStream input,
@@ -1530,13 +1557,12 @@ public abstract class GeneratedMessageLite<
Object visitOneofLazyMessage(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);
- LazyFieldLite visitLazyMessage(
- boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other);
+ LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other);
<T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
BooleanList visitBooleanList(BooleanList mine, BooleanList other);
@@ -1686,7 +1712,7 @@ public abstract class GeneratedMessageLite<
}
throw NOT_EQUALS;
}
-
+
@Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
@@ -1694,7 +1720,7 @@ public abstract class GeneratedMessageLite<
}
throw NOT_EQUALS;
}
-
+
@Override
public void visitOneofNotSet(boolean minePresent) {
if (minePresent) {
@@ -1716,13 +1742,17 @@ public abstract class GeneratedMessageLite<
return mine;
}
-
+
@Override
public LazyFieldLite visitLazyMessage(
- boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
- if (!minePresent && !otherPresent) {
- return mine;
- } else if (minePresent && otherPresent && mine.equals(other)) {
+ LazyFieldLite mine, LazyFieldLite other) {
+ if (mine == null && other == null) {
+ return null;
+ }
+ if (mine == null || other == null) {
+ throw NOT_EQUALS;
+ }
+ if (mine.equals(other)) {
return mine;
}
throw NOT_EQUALS;
@@ -1813,7 +1843,7 @@ public abstract class GeneratedMessageLite<
// 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.
-
+
private int hashCode = 0;
@Override
@@ -1909,7 +1939,7 @@ public abstract class GeneratedMessageLite<
hashCode = (53 * hashCode) + mine.hashCode();
return mine;
}
-
+
@Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
return visitMessage((MessageLite) mine, (MessageLite) other);
@@ -1918,7 +1948,7 @@ public abstract class GeneratedMessageLite<
@Override
public void visitOneofNotSet(boolean minePresent) {
if (minePresent) {
- throw new IllegalStateException(); // Can't happen if other == this.
+ throw new IllegalStateException(); // Can't happen if other == this.
}
}
@@ -1939,9 +1969,14 @@ public abstract class GeneratedMessageLite<
}
@Override
- public LazyFieldLite visitLazyMessage(
- boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
- hashCode = (53 * hashCode) + mine.hashCode();
+ public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
+ final int protoHash;
+ if (mine != null) {
+ protoHash = mine.hashCode();
+ } else {
+ protoHash = 37;
+ }
+ hashCode = (53 * hashCode) + protoHash;
return mine;
}
@@ -1996,7 +2031,7 @@ public abstract class GeneratedMessageLite<
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();
@@ -2064,7 +2099,7 @@ public abstract class GeneratedMessageLite<
@Override
public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
- return other;
+ return other;
}
@Override
@@ -2074,29 +2109,26 @@ public abstract class GeneratedMessageLite<
@Override
public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
- return other;
+ return other;
}
@Override
public Object visitOneofString(boolean minePresent, Object mine, Object other) {
- return other;
+ return other;
}
@Override
public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
- return other;
+ return other;
}
@Override
public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
- if (minePresent) {
- LazyFieldLite lazy = (LazyFieldLite) mine;
- lazy.merge((LazyFieldLite) other);
- return lazy;
- }
- return other;
+ LazyFieldLite lazy = minePresent ? (LazyFieldLite) mine : new LazyFieldLite();
+ lazy.merge((LazyFieldLite) other);
+ return lazy;
}
-
+
@Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
if (minePresent) {
@@ -2104,7 +2136,7 @@ public abstract class GeneratedMessageLite<
}
return other;
}
-
+
@Override
public void visitOneofNotSet(boolean minePresent) {
return;
@@ -2121,12 +2153,13 @@ public abstract class GeneratedMessageLite<
}
@Override
- public LazyFieldLite visitLazyMessage(
- boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
- // LazyFieldLite's are never null so we can just copy across. Necessary to avoid leakage
- // from builder into immutable message.
- // TODO(dweis): Change to null sentinels?
- mine.merge(other);
+ public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
+ if (other != null) {
+ if (mine == null) {
+ mine = new LazyFieldLite();
+ }
+ mine.merge(other);
+ }
return mine;
}
@@ -2140,7 +2173,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2154,7 +2187,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2168,7 +2201,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2182,7 +2215,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2196,7 +2229,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2210,7 +2243,7 @@ public abstract class GeneratedMessageLite<
}
mine.addAll(other);
}
-
+
return size > 0 ? mine : other;
}
@@ -2232,10 +2265,15 @@ public abstract class GeneratedMessageLite<
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) {
- mine.mergeFrom(other);
+ if (!other.isEmpty()) {
+ if (!mine.isMutable()) {
+ mine = mine.mutableCopy();
+ }
+ mine.mergeFrom(other);
+ }
return mine;
}
}
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 6d6ece5a..2f526e3f 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -38,25 +38,27 @@ 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 {
-
+final class IntArrayList
+ extends AbstractProtobufList<Integer>
+ implements IntList, RandomAccess {
+
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.
@@ -71,13 +73,14 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
}
/**
- * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
+ * Constructs a new mutable {@code IntArrayList}
+ * containing the same elements as {@code other}.
*/
- private IntArrayList(int[] array, int size) {
- this.array = array;
+ private IntArrayList(int[] other, int size) {
+ array = other;
this.size = size;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -90,14 +93,14 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
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;
}
@@ -117,7 +120,7 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
}
return new IntArrayList(Arrays.copyOf(array, capacity), size);
}
-
+
@Override
public Integer get(int index) {
return getInt(index);
@@ -169,7 +172,7 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
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);
@@ -177,10 +180,10 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
// 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;
@@ -194,38 +197,38 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
@Override
public boolean addAll(Collection<? extends Integer> collection) {
ensureIsMutable();
-
+
if (collection == null) {
throw new NullPointerException();
}
-
+
// 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();
@@ -254,7 +257,7 @@ final class IntArrayList extends AbstractProtobufList<Integer> implements IntLis
/**
* 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/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index bc4475d1..5a772e3a 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -38,25 +38,27 @@ 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 {
-
+final class LongArrayList
+ extends AbstractProtobufList<Long>
+ implements LongList, RandomAccess {
+
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.
@@ -71,33 +73,34 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
}
/**
- * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
+ * Constructs a new mutable {@code LongArrayList}
+ * containing the same elements as {@code other}.
*/
- private LongArrayList(long[] array, int size) {
- this.array = array;
+ private LongArrayList(long[] other, int size) {
+ array = other;
this.size = size;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
- if (!(o instanceof IntArrayList)) {
+ 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;
}
@@ -117,7 +120,7 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
}
return new LongArrayList(Arrays.copyOf(array, capacity), size);
}
-
+
@Override
public Long get(int index) {
return getLong(index);
@@ -169,7 +172,7 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
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);
@@ -177,10 +180,10 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
// 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;
@@ -194,38 +197,38 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
@Override
public boolean addAll(Collection<? extends Long> collection) {
ensureIsMutable();
-
+
if (collection == null) {
throw new NullPointerException();
}
-
+
// 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();
@@ -254,7 +257,7 @@ final class LongArrayList extends AbstractProtobufList<Long> implements LongList
/**
* 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 31414bb4..117cd911 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -41,63 +41,83 @@ import java.util.TreeMap;
/**
* 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. */
+ 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.getMessage()).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 @@ public final class MapEntry<K, V> extends AbstractMessage {
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 final class MapEntry<K, V> extends AbstractMessage {
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);
}
@Override
public MapEntry<K, V> getDefaultInstanceForType() {
- return metadata.defaultInstance;
+ return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
}
@Override
@@ -157,8 +185,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@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 @@ public final class MapEntry<K, V> extends AbstractMessage {
}
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,44 @@ public final class MapEntry<K, V> extends AbstractMessage {
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 Builder(Metadata<K, V> metadata) {
- this.metadata = metadata;
- this.data = metadata.defaultInstance.data;
- this.dataBuilder = null;
+ this(metadata, metadata.defaultKey, metadata.defaultValue);
}
-
- private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+
+ private Builder(Metadata<K, V> metadata, K key, V value) {
this.metadata = metadata;
- this.data = data;
- this.dataBuilder = null;
+ this.key = key;
+ this.value = value;
}
-
+
public K getKey() {
- return dataBuilder == null ? data.getKey() : dataBuilder.getKey();
+ return key;
}
-
+
public V getValue() {
- return dataBuilder == null ? data.getValue() : dataBuilder.getValue();
- }
-
- private void ensureMutable() {
- if (dataBuilder == null) {
- dataBuilder = data.toBuilder();
- }
+ return value;
}
-
+
public Builder<K, V> setKey(K key) {
- ensureMutable();
- dataBuilder.setKey(key);
+ this.key = key;
return this;
}
-
+
public Builder<K, V> clearKey() {
- ensureMutable();
- dataBuilder.clearKey();
+ this.key = metadata.defaultKey;
return this;
}
-
+
public Builder<K, V> setValue(V value) {
- ensureMutable();
- dataBuilder.setValue(value);
+ this.value = value;
return this;
}
-
+
public Builder<K, V> clearValue() {
- ensureMutable();
- dataBuilder.clearValue();
+ this.value = metadata.defaultValue;
return this;
}
@@ -281,29 +296,24 @@ public final class MapEntry<K, V> extends AbstractMessage {
@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 +322,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
throw new RuntimeException(
"\"" + field.getFullName() + "\" is not a message value field.");
}
- return ((Message) data.getValue()).newBuilderForType();
+ return ((Message) value).newBuilderForType();
}
@SuppressWarnings("unchecked")
@@ -362,22 +372,17 @@ public final class MapEntry<K, V> extends AbstractMessage {
@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));
@@ -398,8 +403,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
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,13 +413,13 @@ public final class MapEntry<K, V> extends AbstractMessage {
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();
@@ -423,11 +427,14 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
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);
}
}
+
+ private static <V> boolean isInitialized(Metadata metadata, V value) {
+ if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
+ return ((MessageLite) value).isInitialized();
+ }
+ return true;
+ }
}
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 12c64abb..22aef8f9 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -31,80 +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<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
- 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,
@@ -112,80 +106,20 @@ public class MapEntryLite<K, V>
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);
- }
- 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> 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 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;
+ 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 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) {
@@ -202,136 +136,91 @@ public class MapEntryLite<K, V>
}
}
- @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);
+ /**
+ * 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);
}
- @Override
- public MapEntryLite<K, V> getDefaultInstanceForType() {
- return metadata.defaultInstance;
+ /**
+ * 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 int computeMessageSize(int fieldNumber, K key, V value) {
+ return CodedOutputStream.computeTagSize(fieldNumber)
+ + CodedOutputStream.computeLengthDelimitedFieldSize(
+ computeSerializedSize(metadata, key, value));
}
- @Override
- public boolean isInitialized() {
- if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
- return ((MessageLite) value).isInitialized();
+ /**
+ * 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);
+ }
+
+ 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;
+ }
+ 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);
}
/**
- * Builder used to create {@link MapEntryLite} messages.
+ * 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 static class Builder<K, V>
- extends AbstractMessageLite.Builder<MapEntryLite<K, V>, 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;
- }
-
- @Override
- public Builder<K, V> clear() {
- this.key = metadata.defaultInstance.key;
- this.value = metadata.defaultInstance.value;
- return this;
- }
-
- @Override
- public MapEntryLite<K, V> build() {
- MapEntryLite<K, V> result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
+ 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;
}
- 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;
- }
-
- 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);
}
- @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;
- }
-
- @Override
- protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
- throw new UnsupportedOperationException();
- }
+ input.checkLastTagWas(0);
+ input.popLimit(oldLimit);
+ map.put(key, value);
}
}
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 907f0f71..a6109f98 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,26 @@
package com.google.protobuf;
-import com.google.protobuf.MapFieldLite.MutatabilityAwareMap;
-
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 +57,21 @@ import java.util.Map;
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,26 +79,26 @@ public class MapField<K, V> implements MutabilityOracle {
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
public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
MapEntry<K, V> entry = (MapEntry<K, V>) message;
@@ -109,10 +110,10 @@ public class MapField<K, V> implements MutabilityOracle {
return defaultEntry;
}
}
-
+
private final Converter<K, V> converter;
-
+
private MapField(
Converter<K, V> converter,
StorageMode mode,
@@ -123,34 +124,34 @@ public class MapField<K, V> implements MutabilityOracle {
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);
@@ -173,7 +174,7 @@ public class MapField<K, V> implements MutabilityOracle {
}
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) {
@@ -186,7 +187,7 @@ public class MapField<K, V> implements MutabilityOracle {
}
return Collections.unmodifiableMap(mapData);
}
-
+
/** Gets a mutable Map view of this MapField. */
public Map<K, V> getMutableMap() {
if (mode != StorageMode.MAP) {
@@ -194,20 +195,20 @@ public class MapField<K, V> implements MutabilityOracle {
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) {
@@ -217,18 +218,18 @@ public class MapField<K, V> implements MutabilityOracle {
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) {
@@ -241,7 +242,7 @@ public class MapField<K, V> implements MutabilityOracle {
}
return Collections.unmodifiableList(listData);
}
-
+
/** Gets a mutable List view of this MapField. */
List<Message> getMutableList() {
if (mode != StorageMode.LIST) {
@@ -253,7 +254,7 @@ public class MapField<K, V> implements MutabilityOracle {
}
return listData;
}
-
+
/**
* Gets the default instance of the message stored in the list view of this
* map field.
@@ -261,7 +262,7 @@ public class MapField<K, V> implements MutabilityOracle {
Message getMapEntryMessageDefaultInstance() {
return converter.getMessageDefaultInstance();
}
-
+
/**
* Makes this list immutable. All subsequent modifications will throw an
* {@link UnsupportedOperationException}.
@@ -269,14 +270,14 @@ public class MapField<K, V> implements MutabilityOracle {
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()
*/
@@ -286,4 +287,338 @@ public class MapField<K, V> implements MutabilityOracle {
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();
+ 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/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index 960b6339..3c0ad89a 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -33,71 +33,85 @@ package com.google.protobuf;
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() {
+ this.isMutable = true;
+ }
+
private MapFieldLite(Map<K, V> mapData) {
- this.mapData = new MutatabilityAwareMap<K, V>(this, 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(Collections.emptyMap());
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>());
+
+ public void mergeFrom(MapFieldLite<K, V> other) {
+ ensureMutable();
+ if (!other.isEmpty()) {
+ putAll(other);
+ }
+ }
+
+ @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();
+ clear();
}
-
- /** Gets the content of this MapField as a read-only Map. */
- public Map<K, V> getMap() {
- return Collections.unmodifiableMap(mapData);
+
+ @Override public V put(K key, V value) {
+ ensureMutable();
+ return super.put(key, value);
}
-
- /** Gets a mutable Map view of this MapField. */
- public Map<K, V> getMutableMap() {
- return mapData;
+
+ public V put(Map.Entry<K, V> entry) {
+ return put(entry.getKey(), entry.getValue());
}
-
- public void mergeFrom(MapFieldLite<K, V> other) {
- mapData.putAll(copy(other.mapData));
+
+ @Override public void putAll(Map<? extends K, ? extends V> m) {
+ ensureMutable();
+ super.putAll(m);
}
-
- public void clear() {
- mapData.clear();
+
+ @Override public V remove(Object key) {
+ ensureMutable();
+ return super.remove(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 +134,16 @@ public final class MapFieldLite<K, V> implements MutabilityOracle {
}
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 +166,14 @@ public final class MapFieldLite<K, V> implements MutabilityOracle {
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 +181,7 @@ public final class MapFieldLite<K, V> implements MutabilityOracle {
}
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 +195,12 @@ public final class MapFieldLite<K, V> implements MutabilityOracle {
}
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 +208,17 @@ public final class MapFieldLite<K, V> implements MutabilityOracle {
public void makeImmutable() {
isMutable = false;
}
-
+
/**
* Returns whether this field can be modified.
*/
public boolean isMutable() {
return isMutable;
}
-
- @Override
- public 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.
+ private void ensureMutable() {
+ if (!isMutable()) {
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/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index 7b791d9e..3d73efb3 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -364,7 +364,6 @@ class MessageReflection {
* Finishes the merge and returns the underlying object.
*/
Object finish();
-
}
static class BuilderAdapter implements MergeTarget {
@@ -549,7 +548,6 @@ class MessageReflection {
public Object finish() {
return builder.buildPartial();
}
-
}
@@ -713,7 +711,6 @@ class MessageReflection {
throw new UnsupportedOperationException(
"finish() called on FieldSet object");
}
-
}
/**
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 00000000..77b61b5f
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
@@ -0,0 +1,708 @@
+// 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.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) {
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ 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) {
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ 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) {
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ 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) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ // 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/SingleFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
new file mode 100644
index 00000000..fb1f76a7
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
@@ -0,0 +1,241 @@
+// 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;
+
+/**
+ * {@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) {
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ this.message = 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) {
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ this.message = 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/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index c1c328fc..ff13675d 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -661,6 +661,14 @@ public final class TextFormat {
nextToken();
}
+ int getPreviousLine() {
+ return previousLine;
+ }
+
+ int getPreviousColumn() {
+ return previousColumn;
+ }
+
int getLine() {
return line;
}
@@ -1374,6 +1382,28 @@ public final class TextFormat {
return text;
}
+ // Check both unknown fields and unknown extensions and log warming 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
@@ -1387,9 +1417,13 @@ public final class TextFormat {
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);
}
@@ -1399,9 +1433,11 @@ public final class TextFormat {
*/
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);
+ mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder,
+ unknownFields);
}
/**
@@ -1411,7 +1447,8 @@ public final class TextFormat {
private void mergeField(final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target,
- TextFormatParseInfoTree.Builder parseTreeBuilder)
+ TextFormatParseInfoTree.Builder parseTreeBuilder,
+ List<String> unknownFields)
throws ParseException {
FieldDescriptor field = null;
int startLine = tokenizer.getLine();
@@ -1432,13 +1469,9 @@ public final class TextFormat {
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(
@@ -1473,16 +1506,9 @@ public final class TextFormat {
}
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);
}
}
@@ -1511,15 +1537,15 @@ public final class TextFormat {
TextFormatParseInfoTree.Builder childParseTreeBuilder =
parseTreeBuilder.getBuilderForSubMessageField(field);
consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
- childParseTreeBuilder);
+ childParseTreeBuilder, unknownFields);
} else {
consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
- parseTreeBuilder);
+ parseTreeBuilder, unknownFields);
}
} else {
tokenizer.consume(":"); // required
- consumeFieldValues(
- tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+ consumeFieldValues(tokenizer, extensionRegistry, target, field,
+ extension, parseTreeBuilder, unknownFields);
}
if (parseTreeBuilder != null) {
@@ -1544,14 +1570,15 @@ public final class TextFormat {
final MessageReflection.MergeTarget target,
final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension,
- final TextFormatParseInfoTree.Builder parseTreeBuilder)
+ 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("[")) {
while (true) {
consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
- parseTreeBuilder);
+ parseTreeBuilder, unknownFields);
if (tokenizer.tryConsume("]")) {
// End of list.
break;
@@ -1559,8 +1586,8 @@ public final class TextFormat {
tokenizer.consume(",");
}
} else {
- consumeFieldValue(
- tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+ consumeFieldValue(tokenizer, extensionRegistry, target, field,
+ extension, parseTreeBuilder, unknownFields);
}
}
@@ -1574,7 +1601,8 @@ public final class TextFormat {
final MessageReflection.MergeTarget target,
final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension,
- final TextFormatParseInfoTree.Builder parseTreeBuilder)
+ final TextFormatParseInfoTree.Builder parseTreeBuilder,
+ List<String> unknownFields)
throws ParseException {
Object value = null;
@@ -1596,7 +1624,8 @@ public final class TextFormat {
throw tokenizer.parseException(
"Expected \"" + endToken + "\".");
}
- mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder);
+ mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder,
+ unknownFields);
}
value = subField.finish();
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 c906420d..6d33d3a8 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -57,6 +57,7 @@ import java.util.TreeMap;
* @author kenton@google.com Kenton Varda
*/
public final class UnknownFieldSet implements MessageLite {
+
private UnknownFieldSet() {}
/** Create a new {@link Builder}. */
@@ -130,7 +131,8 @@ public final class UnknownFieldSet implements MessageLite {
@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);
}
}
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 0fbf4d40..e72a6b4d 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -42,6 +42,23 @@ import java.nio.ByteBuffer;
* 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 {
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 00000000..6a4787d1
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -0,0 +1,210 @@
+// 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 sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Utility class for working with unsafe operations.
+ */
+// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
+final class UnsafeUtil {
+ private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
+ supportsUnsafeByteBufferOperations();
+ private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+ private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+ private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
+
+ private UnsafeUtil() {
+ }
+
+ static boolean hasUnsafeArrayOperations() {
+ return HAS_UNSAFE_ARRAY_OPERATIONS;
+ }
+
+ static boolean hasUnsafeByteBufferOperations() {
+ return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
+ }
+
+ static long getArrayBaseOffset() {
+ return ARRAY_BASE_OFFSET;
+ }
+
+ static byte getByte(byte[] target, long offset) {
+ return UNSAFE.getByte(target, offset);
+ }
+
+ static void putByte(byte[] target, long offset, byte value) {
+ UNSAFE.putByte(target, offset, value);
+ }
+
+ static void copyMemory(
+ byte[] src, long srcOffset, byte[] target, long targetOffset, long length) {
+ UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
+ }
+
+ static long getLong(byte[] target, long offset) {
+ return UNSAFE.getLong(target, offset);
+ }
+
+ static byte getByte(long address) {
+ return UNSAFE.getByte(address);
+ }
+
+ static void putByte(long address, byte value) {
+ UNSAFE.putByte(address, value);
+ }
+
+ static long getLong(long address) {
+ return UNSAFE.getLong(address);
+ }
+
+ static void copyMemory(long srcAddress, long targetAddress, long length) {
+ UNSAFE.copyMemory(srcAddress, targetAddress, length);
+ }
+
+ /**
+ * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
+ */
+ static long addressOffset(ByteBuffer buffer) {
+ return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ }
+
+ /**
+ * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
+ */
+ private static sun.misc.Unsafe getUnsafe() {
+ sun.misc.Unsafe unsafe = null;
+ try {
+ unsafe =
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<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;
+ }
+
+ /**
+ * Indicates whether or not unsafe array operations are supported on this platform.
+ */
+ private static boolean supportsUnsafeArrayOperations() {
+ boolean supported = false;
+ if (UNSAFE != null) {
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ clazz.getMethod("arrayBaseOffset", Class.class);
+ clazz.getMethod("getByte", Object.class, long.class);
+ clazz.getMethod("putByte", Object.class, long.class, byte.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ clazz.getMethod(
+ "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+ supported = true;
+ } catch (Throwable e) {
+ // Do nothing.
+ }
+ }
+ return supported;
+ }
+
+ private static boolean supportsUnsafeByteBufferOperations() {
+ boolean supported = false;
+ if (UNSAFE != null) {
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("getByte", long.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ clazz.getMethod("putByte", long.class, byte.class);
+ clazz.getMethod("getLong", long.class);
+ clazz.getMethod("copyMemory", long.class, long.class, long.class);
+ supported = true;
+ } catch (Throwable e) {
+ // Do nothing.
+ }
+ }
+ return supported;
+ }
+
+ /**
+ * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
+ */
+ private static int byteArrayBaseOffset() {
+ return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
+ }
+
+ /**
+ * 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 || UNSAFE == null ? -1 : UNSAFE.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;
+ }
+}
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 308c69e9..5b80d405 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -30,18 +30,16 @@
package com.google.protobuf;
+import static com.google.protobuf.UnsafeUtil.addressOffset;
+import static com.google.protobuf.UnsafeUtil.getArrayBaseOffset;
+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_SURROGATE;
import static java.lang.Character.isSurrogatePair;
import static java.lang.Character.toCodePoint;
-import java.lang.reflect.Field;
-import java.nio.Buffer;
import java.nio.ByteBuffer;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* A set of low-level, high-performance static utility methods related
@@ -79,7 +77,6 @@ import java.util.logging.Logger;
*/
// TODO(nathanmittler): Copy changes in this class back to Guava
final class Utf8 {
- private static final Logger logger = Logger.getLogger(Utf8.class.getName());
/**
* UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations
@@ -237,7 +234,7 @@ final class Utf8 {
// 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);
}
}
@@ -991,23 +988,11 @@ final class Utf8 {
* {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
*/
static final class UnsafeProcessor extends Processor {
- private static final sun.misc.Unsafe UNSAFE = getUnsafe();
- private static final long BUFFER_ADDRESS_OFFSET =
- fieldOffset(field(Buffer.class, "address"));
- private static final int ARRAY_BASE_OFFSET = byteArrayBaseOffset();
-
- /**
- * We only use Unsafe operations if we have access to direct {@link ByteBuffer}'s address
- * and the array base offset is a multiple of 8 (needed by Unsafe.getLong()).
- */
- private static final boolean AVAILABLE =
- BUFFER_ADDRESS_OFFSET != -1 && ARRAY_BASE_OFFSET % 8 == 0;
-
/**
* Indicates whether or not all required unsafe operations are supported on this platform.
*/
static boolean isAvailable() {
- return AVAILABLE;
+ return hasUnsafeArrayOperations() && hasUnsafeByteBufferOperations();
}
@Override
@@ -1016,8 +1001,8 @@ final class Utf8 {
throw new ArrayIndexOutOfBoundsException(
String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
}
- long offset = ARRAY_BASE_OFFSET + index;
- final long offsetLimit = ARRAY_BASE_OFFSET + limit;
+ long offset = getArrayBaseOffset() + index;
+ final long offsetLimit = getArrayBaseOffset() + limit;
if (state != COMPLETE) {
// The previous decoding operation was incomplete (or malformed).
// We look for a well-formed sequence consisting of bytes from
@@ -1038,7 +1023,7 @@ final class Utf8 {
// leading position and overlong 2-byte form.
if (byte1 < (byte) 0xC2
// byte2 trailing-byte test
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
@@ -1047,7 +1032,7 @@ final class Utf8 {
// Get byte2 from saved state or array
int byte2 = (byte) ~(state >> 8);
if (byte2 == 0) {
- byte2 = UNSAFE.getByte(bytes, offset++);
+ byte2 = UnsafeUtil.getByte(bytes, offset++);
if (offset >= offsetLimit) {
return incompleteStateFor(byte1, byte2);
}
@@ -1058,7 +1043,7 @@ final class Utf8 {
// illegal surrogate codepoint?
|| (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
// byte3 trailing-byte test
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
} else {
@@ -1068,7 +1053,7 @@ final class Utf8 {
int byte2 = (byte) ~(state >> 8);
int byte3 = 0;
if (byte2 == 0) {
- byte2 = UNSAFE.getByte(bytes, offset++);
+ byte2 = UnsafeUtil.getByte(bytes, offset++);
if (offset >= offsetLimit) {
return incompleteStateFor(byte1, byte2);
}
@@ -1076,7 +1061,7 @@ final class Utf8 {
byte3 = (byte) (state >> 16);
}
if (byte3 == 0) {
- byte3 = UNSAFE.getByte(bytes, offset++);
+ byte3 = UnsafeUtil.getByte(bytes, offset++);
if (offset >= offsetLimit) {
return incompleteStateFor(byte1, byte2, byte3);
}
@@ -1095,7 +1080,7 @@ final class Utf8 {
// byte3 trailing-byte test
|| byte3 > (byte) 0xBF
// byte4 trailing-byte test
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
}
@@ -1134,7 +1119,7 @@ final class Utf8 {
// leading position and overlong 2-byte form.
if (byte1 < (byte) 0xC2
// byte2 trailing-byte test
- || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
@@ -1143,7 +1128,7 @@ final class Utf8 {
// Get byte2 from saved state or array
int byte2 = (byte) ~(state >> 8);
if (byte2 == 0) {
- byte2 = UNSAFE.getByte(address++);
+ byte2 = UnsafeUtil.getByte(address++);
if (address >= addressLimit) {
return incompleteStateFor(byte1, byte2);
}
@@ -1154,7 +1139,7 @@ final class Utf8 {
// illegal surrogate codepoint?
|| (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
// byte3 trailing-byte test
- || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
} else {
@@ -1164,7 +1149,7 @@ final class Utf8 {
int byte2 = (byte) ~(state >> 8);
int byte3 = 0;
if (byte2 == 0) {
- byte2 = UNSAFE.getByte(address++);
+ byte2 = UnsafeUtil.getByte(address++);
if (address >= addressLimit) {
return incompleteStateFor(byte1, byte2);
}
@@ -1172,7 +1157,7 @@ final class Utf8 {
byte3 = (byte) (state >> 16);
}
if (byte3 == 0) {
- byte3 = UNSAFE.getByte(address++);
+ byte3 = UnsafeUtil.getByte(address++);
if (address >= addressLimit) {
return incompleteStateFor(byte1, byte2, byte3);
}
@@ -1191,7 +1176,7 @@ final class Utf8 {
// byte3 trailing-byte test
|| byte3 > (byte) 0xBF
// byte4 trailing-byte test
- || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
}
@@ -1202,7 +1187,7 @@ final class Utf8 {
@Override
int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
- long outIx = ARRAY_BASE_OFFSET + offset;
+ long outIx = getArrayBaseOffset() + offset;
final long outLimit = outIx + length;
final int inLimit = in.length();
if (inLimit > length || out.length - length < offset) {
@@ -1215,25 +1200,25 @@ final class Utf8 {
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
int inIx = 0;
for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
- UNSAFE.putByte(out, outIx++, (byte) c);
+ UnsafeUtil.putByte(out, outIx++, (byte) c);
}
if (inIx == inLimit) {
// We're done, it was ASCII encoded.
- return (int) (outIx - ARRAY_BASE_OFFSET);
+ return (int) (outIx - getArrayBaseOffset());
}
for (char c; inIx < inLimit; ++inIx) {
c = in.charAt(inIx);
if (c < 0x80 && outIx < outLimit) {
- UNSAFE.putByte(out, outIx++, (byte) c);
+ UnsafeUtil.putByte(out, outIx++, (byte) c);
} else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
- UNSAFE.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+ 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
- UNSAFE.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+ 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
@@ -1242,10 +1227,10 @@ final class Utf8 {
throw new UnpairedSurrogateException((inIx - 1), inLimit);
}
int codePoint = toCodePoint(c, low);
- UNSAFE.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
- UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
+ 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)))) {
@@ -1258,7 +1243,7 @@ final class Utf8 {
}
// All bytes have been encoded.
- return (int) (outIx - ARRAY_BASE_OFFSET);
+ return (int) (outIx - getArrayBaseOffset());
}
@Override
@@ -1277,7 +1262,7 @@ final class Utf8 {
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
int inIx = 0;
for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
- UNSAFE.putByte(outIx++, (byte) c);
+ UnsafeUtil.putByte(outIx++, (byte) c);
}
if (inIx == inLimit) {
// We're done, it was ASCII encoded.
@@ -1288,15 +1273,15 @@ final class Utf8 {
for (char c; inIx < inLimit; ++inIx) {
c = in.charAt(inIx);
if (c < 0x80 && outIx < outLimit) {
- UNSAFE.putByte(outIx++, (byte) c);
+ UnsafeUtil.putByte(outIx++, (byte) c);
} else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
- UNSAFE.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+ 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
- UNSAFE.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+ 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
@@ -1305,10 +1290,10 @@ final class Utf8 {
throw new UnpairedSurrogateException((inIx - 1), inLimit);
}
int codePoint = toCodePoint(c, low);
- UNSAFE.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
- UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
+ 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)))) {
@@ -1349,7 +1334,7 @@ final class Utf8 {
// we're 8-byte aligned.
final int unaligned = (int) offset & 7;
for (int j = unaligned; j > 0; j--) {
- if (UNSAFE.getByte(bytes, offset++) < 0) {
+ if (UnsafeUtil.getByte(bytes, offset++) < 0) {
return unaligned - j;
}
}
@@ -1358,7 +1343,7 @@ final class Utf8 {
// 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 && (UNSAFE.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
+ for (; remaining >= 8 && (UnsafeUtil.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
offset += 8, remaining -= 8) {}
return maxChars - remaining;
}
@@ -1379,7 +1364,7 @@ final class Utf8 {
// be read before we're 8-byte aligned.
final int unaligned = (int) address & 7;
for (int j = unaligned; j > 0; j--) {
- if (UNSAFE.getByte(address++) < 0) {
+ if (UnsafeUtil.getByte(address++) < 0) {
return unaligned - j;
}
}
@@ -1388,7 +1373,7 @@ final class Utf8 {
// 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 && (UNSAFE.getLong(address) & ASCII_MASK_LONG) == 0;
+ for (; remaining >= 8 && (UnsafeUtil.getLong(address) & ASCII_MASK_LONG) == 0;
address += 8, remaining -= 8) {}
return maxChars - remaining;
}
@@ -1404,7 +1389,7 @@ final class Utf8 {
// 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 = UNSAFE.getByte(bytes, offset++)) >= 0; --remaining) {
+ for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(bytes, offset++)) >= 0; --remaining) {
}
if (remaining == 0) {
return COMPLETE;
@@ -1423,7 +1408,7 @@ final class Utf8 {
// Simultaneously checks for illegal trailing-byte in
// leading position and overlong 2-byte form.
if (byte1 < (byte) 0xC2
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
@@ -1435,13 +1420,13 @@ final class Utf8 {
remaining -= 2;
final int byte2;
- if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+ 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
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
} else {
@@ -1453,16 +1438,16 @@ final class Utf8 {
remaining -= 3;
final int byte2;
- if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+ 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
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF
// byte4 trailing-byte test
- || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
return MALFORMED;
}
}
@@ -1480,7 +1465,7 @@ final class Utf8 {
// 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 = UNSAFE.getByte(address++)) >= 0; --remaining) {
+ for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(address++)) >= 0; --remaining) {
}
if (remaining == 0) {
return COMPLETE;
@@ -1498,7 +1483,7 @@ final class Utf8 {
// Simultaneously checks for illegal trailing-byte in
// leading position and overlong 2-byte form.
- if (byte1 < (byte) 0xC2 || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ if (byte1 < (byte) 0xC2 || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
@@ -1510,14 +1495,14 @@ final class Utf8 {
}
remaining -= 2;
- final byte byte2 = UNSAFE.getByte(address++);
+ 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
- || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
} else {
@@ -1529,7 +1514,7 @@ final class Utf8 {
}
remaining -= 3;
- final byte byte2 = UNSAFE.getByte(address++);
+ final byte byte2 = UnsafeUtil.getByte(address++);
if (byte2 > (byte) 0xBF
// Check that 1 <= plane <= 16. Tricky optimized form of:
// if (byte1 > (byte) 0xF4 ||
@@ -1537,9 +1522,9 @@ final class Utf8 {
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
|| (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
// byte3 trailing-byte test
- || UNSAFE.getByte(address++) > (byte) 0xBF
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF
// byte4 trailing-byte test
- || UNSAFE.getByte(address++) > (byte) 0xBF) {
+ || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
return MALFORMED;
}
}
@@ -1553,11 +1538,11 @@ final class Utf8 {
return incompleteStateFor(byte1);
}
case 1: {
- return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset));
+ return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset));
}
case 2: {
- return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset),
- UNSAFE.getByte(bytes, offset + 1));
+ return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset),
+ UnsafeUtil.getByte(bytes, offset + 1));
}
default: {
throw new AssertionError();
@@ -1571,112 +1556,17 @@ final class Utf8 {
return incompleteStateFor(byte1);
}
case 1: {
- return incompleteStateFor(byte1, UNSAFE.getByte(address));
+ return incompleteStateFor(byte1, UnsafeUtil.getByte(address));
}
case 2: {
- return incompleteStateFor(byte1, UNSAFE.getByte(address), UNSAFE.getByte(address + 1));
+ return incompleteStateFor(byte1, UnsafeUtil.getByte(address),
+ UnsafeUtil.getByte(address + 1));
}
default: {
throw new AssertionError();
}
}
}
-
- /**
- * 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;
- }
- logger.log(Level.FINEST, "{0}.{1}: {2}",
- new Object[] {clazz.getName(), fieldName, (field != null ? "available" : "unavailable")});
- return field;
- }
-
- /**
- * 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 || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
- }
-
- /**
- * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
- * available.
- */
- private static <T> int byteArrayBaseOffset() {
- return UNSAFE == null ? -1 : UNSAFE.arrayBaseOffset(byte[].class);
- }
-
- /**
- * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
- */
- private static long addressOffset(ByteBuffer buffer) {
- return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
- }
-
- /**
- * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
- * platform.
- */
- private 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;
-
- // Check that this platform supports all of the required unsafe methods.
- checkRequiredMethods(k);
-
- 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.
- }
-
- logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
- unsafe != null ? "available" : "unavailable");
- return unsafe;
- }
-
- /**
- * Verifies that all required methods of {@code sun.misc.Unsafe} are available on this platform.
- */
- private static void checkRequiredMethods(Class<sun.misc.Unsafe> clazz)
- throws NoSuchMethodException, SecurityException {
- // Needed for Unsafe byte[] access
- clazz.getMethod("arrayBaseOffset", Class.class);
- clazz.getMethod("getByte", Object.class, long.class);
- clazz.getMethod("putByte", Object.class, long.class, byte.class);
- clazz.getMethod("getLong", Object.class, long.class);
-
- // Needed for Unsafe Direct ByteBuffer access
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("getByte", long.class);
- clazz.getMethod("getLong", Object.class, long.class);
- clazz.getMethod("putByte", long.class, byte.class);
- clazz.getMethod("getLong", long.class);
- }
}
private Utf8() {}
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 24b96c60..ec139225 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -40,30 +40,31 @@ import java.util.Iterator;
/**
* 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,16 +73,16 @@ public class BooleanArrayListTest extends TestCase {
list.makeImmutable();
assertImmutable(list);
}
-
+
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();
@@ -89,7 +90,7 @@ public class BooleanArrayListTest extends TestCase {
} catch (ConcurrentModificationException e) {
// expected
}
-
+
iterator = list.iterator();
list.add(0, false);
try {
@@ -99,19 +100,19 @@ public class BooleanArrayListTest extends TestCase {
// 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();
@@ -119,19 +120,19 @@ public class BooleanArrayListTest extends TestCase {
// 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();
@@ -139,7 +140,7 @@ public class BooleanArrayListTest extends TestCase {
// expected
}
}
-
+
public void testSize() {
assertEquals(0, BooleanArrayList.emptyList().size());
assertEquals(1, UNARY_LIST.size());
@@ -150,26 +151,26 @@ public class BooleanArrayListTest extends TestCase {
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
@@ -182,17 +183,17 @@ public class BooleanArrayListTest extends TestCase {
// 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();
@@ -201,76 +202,78 @@ public class BooleanArrayListTest extends TestCase {
}
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() {
- assertEquals(0, list.size());
- list.addBoolean(true);
- assertEquals(asList(true), list);
+ public void testAddBoolean() {
+ assertEquals(0, list.size());
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);
@@ -280,92 +283,93 @@ public class BooleanArrayListTest extends TestCase {
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
}
}
-
+
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();
@@ -379,63 +383,63 @@ public class BooleanArrayListTest extends TestCase {
} 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();
@@ -443,7 +447,7 @@ public class BooleanArrayListTest extends TestCase {
// 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/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index ef89b389..b3302441 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -382,6 +382,14 @@ public class DescriptorsTest extends TestCase {
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();
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 85b418c4..8e8e4fe2 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -40,39 +40,40 @@ import java.util.Iterator;
/**
* 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 testModificationWithIteration() {
list.addAll(asList(1D, 2D, 3D, 4D));
Iterator<Double> iterator = list.iterator();
@@ -81,7 +82,7 @@ public class DoubleArrayListTest extends TestCase {
assertEquals(1D, (double) iterator.next());
list.set(0, 1D);
assertEquals(2D, (double) iterator.next());
-
+
list.remove(0);
try {
iterator.next();
@@ -89,7 +90,7 @@ public class DoubleArrayListTest extends TestCase {
} catch (ConcurrentModificationException e) {
// expected
}
-
+
iterator = list.iterator();
list.add(0, 0D);
try {
@@ -99,19 +100,19 @@ public class DoubleArrayListTest extends TestCase {
// 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();
@@ -119,19 +120,19 @@ public class DoubleArrayListTest extends TestCase {
// 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();
@@ -139,35 +140,35 @@ public class DoubleArrayListTest extends TestCase {
// 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();
@@ -182,17 +183,17 @@ public class DoubleArrayListTest extends TestCase {
// 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();
@@ -207,7 +208,7 @@ public class DoubleArrayListTest extends TestCase {
// expected
}
}
-
+
public void testAdd() {
assertEquals(0, list.size());
@@ -217,29 +218,31 @@ public class DoubleArrayListTest extends TestCase {
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);
@@ -248,7 +251,7 @@ public class DoubleArrayListTest extends TestCase {
list.addDouble(3);
assertEquals(asList(2D, 3D), list);
}
-
+
public void testAddAll() {
assertEquals(0, list.size());
@@ -256,17 +259,17 @@ public class DoubleArrayListTest extends TestCase {
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));
@@ -280,96 +283,96 @@ public class DoubleArrayListTest extends TestCase {
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
}
}
-
+
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();
@@ -383,28 +386,28 @@ public class DoubleArrayListTest extends TestCase {
} 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();
@@ -418,28 +421,28 @@ public class DoubleArrayListTest extends TestCase {
} 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();
@@ -447,7 +450,7 @@ public class DoubleArrayListTest extends TestCase {
// 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/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
new file mode 100644
index 00000000..c1246782
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -0,0 +1,245 @@
+// 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 junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 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();
+ }
+
+ /**
+ * 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"));
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * 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 304cec4f..82f4216b 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -152,6 +152,26 @@ public class FieldPresenceTest extends TestCase {
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.
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 88a75743..0e13a598 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -40,39 +40,40 @@ import java.util.Iterator;
/**
* 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 testModificationWithIteration() {
list.addAll(asList(1F, 2F, 3F, 4F));
Iterator<Float> iterator = list.iterator();
@@ -81,7 +82,7 @@ public class FloatArrayListTest extends TestCase {
assertEquals(1F, (float) iterator.next());
list.set(0, 1F);
assertEquals(2F, (float) iterator.next());
-
+
list.remove(0);
try {
iterator.next();
@@ -89,7 +90,7 @@ public class FloatArrayListTest extends TestCase {
} catch (ConcurrentModificationException e) {
// expected
}
-
+
iterator = list.iterator();
list.add(0, 0F);
try {
@@ -99,19 +100,19 @@ public class FloatArrayListTest extends TestCase {
// 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();
@@ -119,19 +120,19 @@ public class FloatArrayListTest extends TestCase {
// 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();
@@ -139,35 +140,35 @@ public class FloatArrayListTest extends TestCase {
// 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();
@@ -182,17 +183,17 @@ public class FloatArrayListTest extends TestCase {
// 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();
@@ -207,7 +208,7 @@ public class FloatArrayListTest extends TestCase {
// expected
}
}
-
+
public void testAdd() {
assertEquals(0, list.size());
@@ -217,28 +218,30 @@ public class FloatArrayListTest extends TestCase {
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());
@@ -248,7 +251,7 @@ public class FloatArrayListTest extends TestCase {
list.addFloat(3);
assertEquals(asList(2F, 3F), list);
}
-
+
public void testAddAll() {
assertEquals(0, list.size());
@@ -256,17 +259,17 @@ public class FloatArrayListTest extends TestCase {
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));
@@ -280,96 +283,96 @@ public class FloatArrayListTest extends TestCase {
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
}
}
-
+
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();
@@ -383,63 +386,63 @@ public class FloatArrayListTest extends TestCase {
} 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();
@@ -447,10 +450,10 @@ public class FloatArrayListTest extends TestCase {
// 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/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index efb8f3e2..e59e3c6e 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -40,35 +40,36 @@ import java.util.Iterator;
/**
* 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);
}
@@ -81,7 +82,7 @@ public class IntArrayListTest extends TestCase {
assertEquals(1, (int) iterator.next());
list.set(0, 1);
assertEquals(2, (int) iterator.next());
-
+
list.remove(0);
try {
iterator.next();
@@ -99,19 +100,19 @@ public class IntArrayListTest extends TestCase {
// 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();
@@ -119,19 +120,19 @@ public class IntArrayListTest extends TestCase {
// 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();
@@ -139,35 +140,35 @@ public class IntArrayListTest extends TestCase {
// 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();
@@ -182,17 +183,17 @@ public class IntArrayListTest extends TestCase {
// 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();
@@ -207,7 +208,7 @@ public class IntArrayListTest extends TestCase {
// expected
}
}
-
+
public void testAdd() {
assertEquals(0, list.size());
@@ -217,28 +218,30 @@ public class IntArrayListTest extends TestCase {
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());
@@ -248,7 +251,7 @@ public class IntArrayListTest extends TestCase {
list.addInt(3);
assertEquals(asList(2, 3), list);
}
-
+
public void testAddAll() {
assertEquals(0, list.size());
@@ -256,17 +259,17 @@ public class IntArrayListTest extends TestCase {
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));
@@ -280,96 +283,96 @@ public class IntArrayListTest extends TestCase {
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
}
}
-
+
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();
@@ -383,63 +386,63 @@ public class IntArrayListTest extends TestCase {
} 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();
@@ -447,7 +450,7 @@ public class IntArrayListTest extends TestCase {
// 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/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
index afe0fffd..e5b11cf1 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -251,6 +251,23 @@ public class LazyMessageLiteTest extends TestCase {
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/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index 88c3e0b2..b3a246dc 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -1630,7 +1630,7 @@ public class LiteTest extends TestCase {
fail();
} catch (InvalidProtocolBufferException expected) {}
}
-
+
public void testMergeFrom_sanity() throws Exception {
TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
byte[] bytes = one.toByteArray();
@@ -1642,7 +1642,19 @@ public class LiteTest extends TestCase {
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();
@@ -2202,6 +2214,21 @@ public class LiteTest extends TestCase {
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() {
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 0a8f9ed2..6aaf85d7 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -40,48 +40,49 @@ import java.util.Iterator;
/**
* 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 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();
@@ -89,7 +90,7 @@ public class LongArrayListTest extends TestCase {
} catch (ConcurrentModificationException e) {
// expected
}
-
+
iterator = list.iterator();
list.add(0, 0L);
try {
@@ -99,19 +100,19 @@ public class LongArrayListTest extends TestCase {
// 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();
@@ -119,19 +120,19 @@ public class LongArrayListTest extends TestCase {
// 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();
@@ -139,35 +140,35 @@ public class LongArrayListTest extends TestCase {
// 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();
@@ -182,17 +183,17 @@ public class LongArrayListTest extends TestCase {
// expected
}
}
-
+
public void testSetLong() {
- list.addLong(2);
- list.addLong(4);
-
- assertEquals(2, list.setLong(0, 0));
- assertEquals(0, list.getLong(0));
+ 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));
- assertEquals(4, list.setLong(1, 0));
- assertEquals(0, list.getLong(1));
-
try {
list.setLong(-1, 0);
fail();
@@ -207,7 +208,7 @@ public class LongArrayListTest extends TestCase {
// expected
}
}
-
+
public void testAdd() {
assertEquals(0, list.size());
@@ -217,28 +218,30 @@ public class LongArrayListTest extends TestCase {
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());
@@ -248,128 +251,128 @@ public class LongArrayListTest extends TestCase {
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
}
}
-
+
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();
@@ -383,63 +386,63 @@ public class LongArrayListTest extends TestCase {
} 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();
@@ -447,7 +450,7 @@ public class LongArrayListTest extends TestCase {
// 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 d79d0029..04d58006 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -30,12 +30,16 @@
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;
@@ -44,34 +48,40 @@ import java.util.Map;
/**
* Unit tests for map fields.
*/
-public class MapForProto2LiteTest extends TestCase {
+public final 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);
-
- 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);
+ 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 +104,22 @@ public class MapForProto2LiteTest 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());
@@ -117,31 +127,42 @@ public class MapForProto2LiteTest extends TestCase {
}
private void updateMapValues(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);
+ 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 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 +175,149 @@ public class MapForProto2LiteTest 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());
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 +326,52 @@ public class MapForProto2LiteTest extends TestCase {
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 +379,14 @@ public class MapForProto2LiteTest 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();
@@ -372,12 +394,61 @@ public class MapForProto2LiteTest extends TestCase {
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(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+ 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(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+ 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(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ }
+
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 +457,26 @@ public class MapForProto2LiteTest 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();
- 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 +484,9 @@ public class MapForProto2LiteTest extends TestCase {
}
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);
@@ -442,17 +512,288 @@ public class MapForProto2LiteTest extends TestCase {
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 73154c0f..e8246bf6 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -31,13 +31,17 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapForProto2TestProto.BizarroTestMap;
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;
@@ -48,7 +52,8 @@ import java.util.Map;
* 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);
@@ -56,27 +61,67 @@ public class MapForProto2Test 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 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())
@@ -87,7 +132,7 @@ public class MapForProto2Test extends TestCase {
.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());
@@ -97,29 +142,29 @@ public class MapForProto2Test 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());
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);
@@ -127,26 +172,78 @@ public class MapForProto2Test 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);
}
+ 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());
@@ -157,37 +254,72 @@ public class MapForProto2Test 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());
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();
@@ -217,7 +349,7 @@ public class MapForProto2Test extends TestCase {
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());
@@ -232,7 +364,7 @@ public class MapForProto2Test extends TestCase {
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()),
@@ -302,48 +434,91 @@ public class MapForProto2Test extends TestCase {
TestMap.Builder builder = TestMap.newBuilder();
TestMap message = builder.build();
assertMapValuesCleared(message);
-
+
builder = message.toBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(builder);
message = builder.build();
assertMapValuesSet(message);
-
+
builder = message.toBuilder();
- updateMapValues(builder);
+ updateMapValuesUsingMutableMap(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);
+ setMapValuesUsingMutableMap(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);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
assertEquals(message.getSerializedSize(), message.toByteString().size());
message = TestMap.parser().parseFrom(message.toByteString());
assertMapValuesSet(message);
-
+
builder = message.toBuilder();
- updateMapValues(builder);
+ updateMapValuesUsingMutableMap(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();
@@ -351,12 +526,61 @@ public class MapForProto2Test extends TestCase {
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(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+ 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(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+ 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(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ }
+
public void testMergeFrom() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
-
+
TestMap.Builder other = TestMap.newBuilder();
other.mergeFrom(message);
assertMapValuesSet(other.build());
@@ -365,7 +589,7 @@ public class MapForProto2Test 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();
@@ -373,16 +597,16 @@ public class MapForProto2Test 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();
@@ -390,26 +614,26 @@ public class MapForProto2Test extends TestCase {
// 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)) {
@@ -428,7 +652,7 @@ public class MapForProto2Test extends TestCase {
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);
@@ -439,7 +663,7 @@ public class MapForProto2Test extends TestCase {
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()) {
@@ -448,9 +672,8 @@ public class MapForProto2Test extends TestCase {
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);
@@ -476,14 +699,14 @@ public class MapForProto2Test 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));
@@ -496,7 +719,7 @@ public class MapForProto2Test 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));
@@ -516,7 +739,7 @@ public class MapForProto2Test 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);
@@ -533,35 +756,35 @@ public class MapForProto2Test 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);
+ setMapValuesUsingMutableMap(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);
+ setMapValuesUsingMutableMap(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.
@@ -570,22 +793,22 @@ public class MapForProto2Test 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();
@@ -593,7 +816,7 @@ public class MapForProto2Test extends TestCase {
// 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();
@@ -646,13 +869,266 @@ public class MapForProto2Test extends TestCase {
public void testIterationOrder() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(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();
+ setMapValuesUsingMutableMap(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);
+
+ setMapValuesUsingMutableMap(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();
+ setMapValuesUsingMutableMap(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
@@ -666,18 +1142,36 @@ public class MapForProto2Test extends TestCase {
message.getDescriptorForType().findFieldByName("map_field"), 0);
assertEquals(2, mapEntry.getAllFields().size());
}
-
+
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 1dc5787d..caef246b 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -30,15 +30,20 @@
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 map_test.MapTestProto.BizarroTestMap;
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;
@@ -49,7 +54,8 @@ import java.util.Map;
* 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);
@@ -78,6 +84,46 @@ public class MapTest extends TestCase {
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())
@@ -120,7 +166,7 @@ public class MapTest extends TestCase {
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);
@@ -148,6 +194,58 @@ public class MapTest extends TestCase {
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());
@@ -180,15 +278,50 @@ public class MapTest extends TestCase {
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();
@@ -218,7 +351,7 @@ public class MapTest extends TestCase {
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 +366,7 @@ public class MapTest extends TestCase {
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()),
@@ -298,32 +431,34 @@ public class MapTest extends TestCase {
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);
+ setMapValuesUsingMutableMap(builder);
message = builder.build();
assertMapValuesSet(message);
builder = message.toBuilder();
- updateMapValues(builder);
+ updateMapValuesUsingMutableMap(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);
+ setMapValuesUsingMutableMap(sourceBuilder);
TestMap source = sourceBuilder.build();
+ assertMapValuesSet(source);
TestMap.Builder destination = TestMap.newBuilder();
copyMapValues(source, destination);
@@ -344,18 +479,76 @@ public class MapTest extends TestCase {
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);
+
+ try {
+ builder.putInt32ToEnumFieldValue(2, 1000); // unknown value.
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ TestMap message = builder.build();
+ assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
+ assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
+ assertEquals(2, 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);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
assertEquals(message.getSerializedSize(), message.toByteString().size());
message = TestMap.parser().parseFrom(message.toByteString());
assertMapValuesSet(message);
builder = message.toBuilder();
- updateMapValues(builder);
+ updateMapValuesUsingMutableMap(builder);
message = builder.build();
assertEquals(message.getSerializedSize(), message.toByteString().size());
message = TestMap.parser().parseFrom(message.toByteString());
@@ -369,9 +562,58 @@ public class MapTest extends TestCase {
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(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+ 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(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+ 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(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+ }
+
public void testMergeFrom() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
TestMap.Builder other = TestMap.newBuilder();
@@ -629,7 +871,7 @@ public class MapTest extends TestCase {
public void testTextFormat() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
String textData = TextFormat.printToString(message);
@@ -643,7 +885,7 @@ public class MapTest extends TestCase {
public void testDynamicMessage() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(builder);
TestMap message = builder.build();
Message dynamicDefaultInstance =
@@ -760,19 +1002,317 @@ public class MapTest extends TestCase {
public void testIterationOrder() throws Exception {
TestMap.Builder builder = TestMap.newBuilder();
- setMapValues(builder);
+ setMapValuesUsingMutableMap(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();
+ setMapValuesUsingMutableMap(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();
+ setMapValuesUsingMutableMap(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);
+
+ setMapValuesUsingMutableMap(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));
+ try {
+ builder.putInt32ToEnumFieldValue(1, -1);
+ fail();
+ } catch (IllegalArgumentException 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();
+ setMapValuesUsingMutableMap(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
+ }
+ }
+
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);
diff --git a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
new file mode 100644
index 00000000..241a4354
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
@@ -0,0 +1,190 @@
+// 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.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 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 RepeatedFieldBuilderV3Test extends TestCase {
+
+ public void testBasicUse() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+ assertEquals(0, builder.getMessage(0).getOptionalInt32());
+ assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+ List<TestAllTypes> list = builder.build();
+ assertEquals(2, list.size());
+ assertEquals(0, list.get(0).getOptionalInt32());
+ assertEquals(1, list.get(1).getOptionalInt32());
+ assertIsUnmodifiable(list);
+
+ // Make sure it doesn't change.
+ List<TestAllTypes> list2 = builder.build();
+ assertSame(list, list2);
+ assertEquals(0, mockParent.getInvalidationCount());
+ }
+
+ public void testGoingBackAndForth() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+ assertEquals(0, builder.getMessage(0).getOptionalInt32());
+ assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+ // Convert to list
+ List<TestAllTypes> list = builder.build();
+ assertEquals(2, list.size());
+ assertEquals(0, list.get(0).getOptionalInt32());
+ assertEquals(1, list.get(1).getOptionalInt32());
+ assertIsUnmodifiable(list);
+
+ // Update 0th item
+ assertEquals(0, mockParent.getInvalidationCount());
+ builder.getBuilder(0).setOptionalString("foo");
+ assertEquals(1, mockParent.getInvalidationCount());
+ list = builder.build();
+ assertEquals(2, list.size());
+ assertEquals(0, list.get(0).getOptionalInt32());
+ assertEquals("foo", list.get(0).getOptionalString());
+ assertEquals(1, list.get(1).getOptionalInt32());
+ assertIsUnmodifiable(list);
+ assertEquals(1, mockParent.getInvalidationCount());
+ }
+
+ public void testVariousMethods() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ 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())
+ .setOptionalInt32(0);
+ builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
+
+ assertEquals(0, builder.getMessage(0).getOptionalInt32());
+ assertEquals(1, builder.getMessage(1).getOptionalInt32());
+ assertEquals(2, builder.getMessage(2).getOptionalInt32());
+ assertEquals(3, builder.getMessage(3).getOptionalInt32());
+
+ assertEquals(0, mockParent.getInvalidationCount());
+ List<TestAllTypes> messages = builder.build();
+ assertEquals(4, messages.size());
+ assertSame(messages, builder.build()); // expect same list
+
+ // Remove a message.
+ builder.remove(2);
+ assertEquals(1, mockParent.getInvalidationCount());
+ assertEquals(3, builder.getCount());
+ assertEquals(0, builder.getMessage(0).getOptionalInt32());
+ assertEquals(1, builder.getMessage(1).getOptionalInt32());
+ assertEquals(3, builder.getMessage(2).getOptionalInt32());
+
+ // Remove a builder.
+ builder.remove(0);
+ assertEquals(1, mockParent.getInvalidationCount());
+ assertEquals(2, builder.getCount());
+ assertEquals(1, builder.getMessage(0).getOptionalInt32());
+ assertEquals(3, builder.getMessage(1).getOptionalInt32());
+
+ // Test clear.
+ builder.clear();
+ assertEquals(1, mockParent.getInvalidationCount());
+ assertEquals(0, builder.getCount());
+ assertTrue(builder.isEmpty());
+ }
+
+ public void testLists() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+ builder.addMessage(0,
+ TestAllTypes.newBuilder().setOptionalInt32(0).build());
+ assertEquals(0, builder.getMessage(0).getOptionalInt32());
+ assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+ // Use list of builders.
+ List<TestAllTypes.Builder> builders = builder.getBuilderList();
+ assertEquals(0, builders.get(0).getOptionalInt32());
+ assertEquals(1, builders.get(1).getOptionalInt32());
+ builders.get(0).setOptionalInt32(10);
+ builders.get(1).setOptionalInt32(11);
+
+ // Use list of protos
+ List<TestAllTypes> protos = builder.getMessageList();
+ assertEquals(10, protos.get(0).getOptionalInt32());
+ assertEquals(11, protos.get(1).getOptionalInt32());
+
+ // Add an item to the builders and verify it's updated in both
+ builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
+ assertEquals(3, builders.size());
+ assertEquals(3, protos.size());
+ }
+
+ 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
+ }
+ }
+ }
+
+ private RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder>
+ 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/SingleFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
new file mode 100644
index 00000000..e3a8d4f4
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
@@ -0,0 +1,155 @@
+// 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.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+
+import junit.framework.TestCase;
+
+/**
+ * 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 SingleFieldBuilderV3Test extends TestCase {
+
+ public void testBasicUseAndInvalidations() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder =
+ new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder>(
+ TestAllTypes.getDefaultInstance(),
+ mockParent,
+ false);
+ assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+ assertEquals(TestAllTypes.getDefaultInstance(),
+ builder.getBuilder().buildPartial());
+ assertEquals(0, mockParent.getInvalidationCount());
+
+ builder.getBuilder().setOptionalInt32(10);
+ assertEquals(0, mockParent.getInvalidationCount());
+ TestAllTypes message = builder.build();
+ assertEquals(10, message.getOptionalInt32());
+
+ // Test that we receive invalidations now that build has been called.
+ assertEquals(0, mockParent.getInvalidationCount());
+ builder.getBuilder().setOptionalInt32(20);
+ assertEquals(1, mockParent.getInvalidationCount());
+
+ // Test that we don't keep getting invalidations on every change
+ builder.getBuilder().setOptionalInt32(30);
+ assertEquals(1, mockParent.getInvalidationCount());
+
+ }
+
+ public void testSetMessage() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder =
+ new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder>(
+ TestAllTypes.getDefaultInstance(),
+ mockParent,
+ false);
+ builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+ assertEquals(0, builder.getMessage().getOptionalInt32());
+
+ // Update message using the builder
+ builder.getBuilder().setOptionalInt32(1);
+ assertEquals(0, mockParent.getInvalidationCount());
+ assertEquals(1, builder.getBuilder().getOptionalInt32());
+ assertEquals(1, builder.getMessage().getOptionalInt32());
+ builder.build();
+ builder.getBuilder().setOptionalInt32(2);
+ assertEquals(2, builder.getBuilder().getOptionalInt32());
+ assertEquals(2, builder.getMessage().getOptionalInt32());
+
+ // Make sure message stays cached
+ assertSame(builder.getMessage(), builder.getMessage());
+ }
+
+ public void testClear() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder =
+ new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder>(
+ TestAllTypes.getDefaultInstance(),
+ mockParent,
+ false);
+ builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+ assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+ builder.clear();
+ assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+
+ builder.getBuilder().setOptionalInt32(1);
+ assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+ builder.clear();
+ assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+ }
+
+ public void testMerge() {
+ TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+ SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder> builder =
+ new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+ TestAllTypesOrBuilder>(
+ TestAllTypes.getDefaultInstance(),
+ mockParent,
+ false);
+
+ // Merge into default field.
+ builder.mergeFrom(TestAllTypes.getDefaultInstance());
+ assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+
+ // Merge into non-default field on existing builder.
+ builder.getBuilder().setOptionalInt32(2);
+ builder.mergeFrom(TestAllTypes.newBuilder()
+ .setOptionalDouble(4.0)
+ .buildPartial());
+ assertEquals(2, builder.getMessage().getOptionalInt32());
+ assertEquals(4.0, builder.getMessage().getOptionalDouble());
+
+ // Merge into non-default field on existing message
+ builder.setMessage(TestAllTypes.newBuilder()
+ .setOptionalInt32(10)
+ .buildPartial());
+ builder.mergeFrom(TestAllTypes.newBuilder()
+ .setOptionalDouble(5.0)
+ .buildPartial());
+ assertEquals(10, builder.getMessage().getOptionalInt32());
+ assertEquals(5.0, builder.getMessage().getOptionalDouble());
+ }
+}
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 08b2a76d..d94f99e3 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -3764,7 +3764,8 @@ public final class TestUtil {
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) {
@@ -3781,7 +3782,7 @@ public final class TestUtil {
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);
}
/**
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 63c17cd0..14783b0a 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -522,15 +522,16 @@ public class TextFormatTest extends TestCase {
"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 \">\".",
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 8f3ca8c6..86cdd286 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
@@ -54,6 +54,7 @@ message TestAllTypes {
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 +82,7 @@ message TestOptionalFieldsOnly {
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/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
index d5418f28..de3336a5 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
@@ -70,6 +70,17 @@ message TestRecursiveMap {
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
+}
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 a9be5166..0c92b0ae 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
@@ -72,3 +72,14 @@ message TestRecursiveMap {
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
+}
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 2280ac03..9eb63fc3 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
@@ -55,9 +55,19 @@ message TestMap {
map<string, int32> string_to_int32_field = 6;
}
-// 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
+}
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 00000000..5fe6ebca
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -0,0 +1,256 @@
+// 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.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;
+
+/**
+ * Utilities to help create/manipulate {@code protobuf/duration.proto}.
+ */
+public final class Durations {
+ static final long DURATION_SECONDS_MIN = -315576000000L;
+ static final long DURATION_SECONDS_MAX = 315576000000L;
+
+ // TODO(kak): Do we want to expose Duration constants for MAX/MIN?
+
+ private Durations() {}
+
+ /**
+ * Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the
+ * range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range
+ * [-999,999,999, +999,999,999].
+ *
+ * <p>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
+ * positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
+ * for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+ */
+ 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>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
+ * positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
+ * for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+ */
+ public static boolean isValid(long seconds, long 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 seconds/nanos are not
+ * a valid {@link Duration}.
+ */
+ private static void checkValid(long seconds, int nanos) {
+ if (!isValid(seconds, nanos)) {
+ throw new IllegalArgumentException(String.format(
+ "Duration is not valid. See proto definition for valid values. "
+ + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]."
+ + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+ + "Nanos must have the same sign as seconds", seconds, nanos));
+ }
+ }
+
+ /**
+ * 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) {
+ long seconds = duration.getSeconds();
+ int nanos = duration.getNanos();
+ checkValid(seconds, nanos);
+
+ 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 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) {
+ return 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) {
+ return 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) {
+ return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
+ }
+
+ /**
+ * Add two durations.
+ */
+ public static Duration add(Duration d1, Duration d2) {
+ return normalizedDuration(d1.getSeconds() + d2.getSeconds(), d1.getNanos() + d2.getNanos());
+ }
+
+ /**
+ * Subtract a duration from another.
+ */
+ public static Duration subtract(Duration d1, Duration d2) {
+ return normalizedDuration(d1.getSeconds() - d2.getSeconds(), d1.getNanos() - d2.getNanos());
+ }
+
+ static Duration normalizedDuration(long seconds, int nanos) {
+ if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+ seconds += nanos / NANOS_PER_SECOND;
+ nanos %= NANOS_PER_SECOND;
+ }
+ if (seconds > 0 && nanos < 0) {
+ nanos += NANOS_PER_SECOND;
+ seconds -= 1;
+ }
+ if (seconds < 0 && nanos > 0) {
+ nanos -= NANOS_PER_SECOND;
+ seconds += 1;
+ }
+ checkValid(seconds, nanos);
+ return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+ }
+}
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 668d65ab..b577495d 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
@@ -38,6 +38,7 @@ 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,22 +60,26 @@ import java.util.logging.Logger;
* intersection to two FieldMasks and traverse all fields specified by the
* FieldMask in a message tree.
*/
-class FieldMaskTree {
+final class FieldMaskTree {
private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
- private static class Node {
- public TreeMap<String, Node> children = new TreeMap<String, Node>();
+ 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 an empty FieldMaskTree.
+ */
+ FieldMaskTree() {}
- /** Creates a FieldMaskTree for a given FieldMask. */
- public FieldMaskTree(FieldMask mask) {
+ /**
+ * Creates a FieldMaskTree for a given FieldMask.
+ */
+ FieldMaskTree(FieldMask mask) {
mergeFromFieldMask(mask);
}
@@ -93,7 +98,7 @@ class FieldMaskTree {
* 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;
@@ -124,15 +129,17 @@ class FieldMaskTree {
/**
* 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();
}
@@ -141,7 +148,9 @@ class FieldMaskTree {
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);
@@ -154,10 +163,9 @@ class FieldMaskTree {
}
/**
- * 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;
}
@@ -188,11 +196,9 @@ class FieldMaskTree {
}
/**
- * 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.");
}
@@ -202,8 +208,8 @@ class FieldMaskTree {
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,
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 96961521..21d11b2c 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 @@ package com.google.protobuf.util;
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.FieldMask;
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 @@ public class FieldMaskUtil {
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 class FieldMaskUtil {
*/
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 @@ public class FieldMaskUtil {
* @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 @@ public class FieldMaskUtil {
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 @@ public class FieldMaskUtil {
}
/**
+ * 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 @@ public class FieldMaskUtil {
* 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 @@ public class FieldMaskUtil {
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 @@ public class FieldMaskUtil {
}
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
@@ -251,7 +280,7 @@ public class FieldMaskUtil {
* destination message fields) when merging.
* Default behavior is to merge the source message field into the
* destination message field.
- */
+ */
public boolean replaceMessageFields() {
return replaceMessageFields;
}
@@ -299,16 +328,15 @@ public class FieldMaskUtil {
* 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 76f3437a..bf70834a 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
@@ -60,6 +60,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
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;
@@ -92,18 +93,17 @@ import java.util.logging.Logger;
* 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);
}
-
+
/**
* A Printer converts protobuf message to JSON format.
*/
@@ -120,11 +120,11 @@ public class JsonFormat {
this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames;
}
-
+
/**
* 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) {
@@ -153,16 +153,15 @@ public class JsonFormat {
public Printer preservingProtoFieldNames() {
return new Printer(registry, includingDefaultValueFields, true);
}
-
+
/**
* Converts a protobuf message to JSON format.
- *
+ *
* @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)
@@ -171,10 +170,9 @@ public class JsonFormat {
/**
* 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);
@@ -194,21 +192,21 @@ public class JsonFormat {
public static Parser parser() {
return new Parser(TypeRegistry.getEmptyTypeRegistry());
}
-
+
/**
* A Parser parses JSON to protobuf message.
*/
public static class Parser {
private final TypeRegistry registry;
-
+
private Parser(TypeRegistry registry) {
- this.registry = registry;
+ this.registry = registry;
}
-
+
/**
* 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) {
@@ -217,29 +215,27 @@ public class JsonFormat {
}
return new Parser(registry);
}
-
+
/**
* 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);
}
-
+
/**
* 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);
@@ -255,8 +251,8 @@ public class JsonFormat {
*/
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() {
@@ -293,8 +289,7 @@ public class JsonFormat {
*/
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;
@@ -306,8 +301,7 @@ public class JsonFormat {
*/
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.Builer can only be used once.");
}
for (Descriptor type : messageTypes) {
addFile(type.getFile());
@@ -345,8 +339,7 @@ public class JsonFormat {
}
if (types.containsKey(message.getFullName())) {
- logger.warning("Type " + message.getFullName()
- + " is added multiple times.");
+ logger.warning("Type " + message.getFullName() + " is added multiple times.");
return;
}
@@ -354,8 +347,7 @@ public class JsonFormat {
}
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>();
}
}
@@ -387,8 +379,7 @@ public class JsonFormat {
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);
}
@@ -450,45 +441,41 @@ public class JsonFormat {
}
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;
- }
-
- private static final Map<String, WellKnownTypePrinter>
- wellKnownTypePrinters = buildWellKnownTypePrinters();
-
- private static Map<String, WellKnownTypePrinter>
- buildWellKnownTypePrinters() {
- Map<String, WellKnownTypePrinter> printers =
- new HashMap<String, WellKnownTypePrinter>();
+ 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>();
// 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);
@@ -499,70 +486,71 @@ public class JsonFormat {
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 {
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.");
@@ -571,12 +559,11 @@ public class JsonFormat {
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
@@ -594,7 +581,7 @@ public class JsonFormat {
print(contentMessage, typeUrl);
}
}
-
+
/** Prints wrapper types (e.g., google.protobuf.Int32Value) */
private void printWrapper(MessageOrBuilder message) throws IOException {
Descriptor descriptor = message.getDescriptorForType();
@@ -606,7 +593,7 @@ public class JsonFormat {
// the whole message.
printSingleFieldValue(valueField, message.getField(valueField));
}
-
+
private ByteString toByteString(MessageOrBuilder message) {
if (message instanceof Message) {
return ((Message) message).toByteString();
@@ -614,26 +601,25 @@ public class JsonFormat {
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();
@@ -644,7 +630,7 @@ public class JsonFormat {
// 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.
@@ -663,7 +649,7 @@ public class JsonFormat {
printSingleFieldValue(entry.getKey(), entry.getValue());
}
}
-
+
/** Prints google.protobuf.ListValue */
private void printListValue(MessageOrBuilder message) throws IOException {
Descriptor descriptor = message.getDescriptorForType();
@@ -675,8 +661,7 @@ public class JsonFormat {
}
/** Prints a regular message with an optional type URL. */
- private void print(MessageOrBuilder message, String typeUrl)
- throws IOException {
+ private void print(MessageOrBuilder message, String typeUrl) throws IOException {
generator.print("{\n");
generator.indent();
@@ -710,7 +695,7 @@ public class JsonFormat {
}
printField(field.getKey(), field.getValue());
}
-
+
// Add line-endings for the last field.
if (printedField) {
generator.print("\n");
@@ -719,8 +704,7 @@ public class JsonFormat {
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() + "\": ");
} else {
@@ -734,10 +718,9 @@ public class JsonFormat {
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) {
@@ -750,10 +733,9 @@ public class JsonFormat {
}
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");
@@ -783,21 +765,20 @@ public class JsonFormat {
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:
@@ -851,7 +832,7 @@ public class JsonFormat {
}
}
break;
-
+
case DOUBLE:
Double doubleValue = (Double) value;
if (doubleValue.isNaN()) {
@@ -895,15 +876,13 @@ public class JsonFormat {
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("\"");
@@ -914,11 +893,9 @@ public class JsonFormat {
}
} else {
if (((EnumValueDescriptor) value).getIndex() == -1) {
- generator.print(
- String.valueOf(((EnumValueDescriptor) value).getNumber()));
+ generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
} else {
- generator.print(
- "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+ generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");
}
}
break;
@@ -947,40 +924,34 @@ public class JsonFormat {
} 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 String getTypeName(String typeUrl)
- throws InvalidProtocolBufferException {
+ private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException {
String[] parts = typeUrl.split("/");
if (parts.length == 1) {
- throw new InvalidProtocolBufferException(
- "Invalid type url found: " + typeUrl);
+ throw new InvalidProtocolBufferException("Invalid type url found: " + typeUrl);
}
return parts[parts.length - 1];
}
-
+
private static class ParserImpl {
private final TypeRegistry registry;
private final JsonParser jsonParser;
-
+
ParserImpl(TypeRegistry registry) {
this.registry = registry;
this.jsonParser = new JsonParser();
}
-
- void merge(Reader json, Message.Builder builder)
- throws IOException {
+
+ void merge(Reader json, Message.Builder builder) throws IOException {
JsonReader reader = new JsonReader(json);
reader.setLenient(false);
merge(jsonParser.parse(reader), builder);
}
-
- 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 +963,36 @@ public class JsonFormat {
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,82 +1003,86 @@ public class JsonFormat {
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(),
+ parsers.put(
+ ListValue.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeListValue(json, builder);
- }
- });
+ @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);
@@ -1116,16 +1092,14 @@ public class JsonFormat {
}
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;
@@ -1133,47 +1107,46 @@ public class JsonFormat {
FieldDescriptor field = fieldNameMap.get(entry.getKey());
if (field == null) {
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;
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) {
@@ -1184,35 +1157,33 @@ public class JsonFormat {
}
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();
@@ -1232,21 +1203,18 @@ public class JsonFormat {
}
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");
@@ -1262,20 +1230,19 @@ public class JsonFormat {
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(
@@ -1290,8 +1257,11 @@ public class JsonFormat {
&& 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) {
@@ -1310,44 +1280,38 @@ public class JsonFormat {
}
}
}
-
- 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.
+ * proto "default" option.
*/
- private Object getDefaultValue(FieldDescriptor field,
- Message.Builder builder) {
+ private Object getDefaultValue(FieldDescriptor field, Message.Builder builder) {
switch (field.getType()) {
case INT32:
case SINT32:
@@ -1377,30 +1341,27 @@ public class JsonFormat {
case GROUP:
return builder.newBuilderForField(field).getDefaultInstanceForType();
default:
- throw new IllegalStateException(
- "Invalid field type: " + field.getType());
+ 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");
+ throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
}
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) {
@@ -1416,9 +1377,8 @@ public class JsonFormat {
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) {
@@ -1434,14 +1394,12 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Not an int32 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) {
@@ -1462,35 +1420,28 @@ public class JsonFormat {
} 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;
}
@@ -1499,11 +1450,10 @@ public class JsonFormat {
}
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")) {
@@ -1521,8 +1471,7 @@ public class JsonFormat {
// 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) {
@@ -1531,19 +1480,17 @@ public class JsonFormat {
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")) {
@@ -1556,36 +1503,32 @@ public class JsonFormat {
// 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);
}
- return ByteString.copyFrom(
- BaseEncoding.base64().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) {
@@ -1602,27 +1545,28 @@ public class JsonFormat {
// 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;
}
@@ -1642,7 +1586,7 @@ public class JsonFormat {
case FLOAT:
return parseFloat(json);
-
+
case DOUBLE:
return parseDouble(json);
@@ -1668,11 +1612,10 @@ public class JsonFormat {
Message.Builder subBuilder = builder.newBuilderForField(field);
merge(json, subBuilder);
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 3033182a..04758473 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 com.google.protobuf.Timestamp;
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 class TimeUtil {
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 @@ public class TimeUtil {
* @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 @@ public class TimeUtil {
*
* @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 @@ public class TimeUtil {
* @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 @@ public class TimeUtil {
*
* @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 @@ public class TimeUtil {
* <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 @@ public class TimeUtil {
* <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 @@ public class TimeUtil {
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 @@ public class TimeUtil {
}
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 00000000..f1f202da
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -0,0 +1,349 @@
+// 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 com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+
+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 {@code protobuf/timestamp.proto}.
+ */
+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;
+
+ // TODO(kak): Do we want to expose Timestamp constants for MAX/MIN?
+
+ 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 Timestamps() {}
+
+ /**
+ * Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the
+ * range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and
+ * 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range [0, +999,999,999].
+ *
+ * <p>Note: Negative second values with fractions must still have non-negative nanos value that
+ * counts forward in time.
+ */
+ 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>Note: Negative second values with fractions must still have non-negative nanos value that
+ * counts forward in time.
+ */
+ public static boolean isValid(long seconds, long 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 seconds/nanos are not
+ * a valid {@link Timestamp}.
+ */
+ private static void checkValid(long seconds, int nanos) {
+ if (!isValid(seconds, nanos)) {
+ throw new IllegalArgumentException(String.format(
+ "Timestamp is not valid. See proto definition for valid values. "
+ + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]."
+ + "Nanos (%s) must be in range [0, +999,999,999].",
+ seconds, nanos));
+ }
+ }
+
+ /**
+ * 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) {
+ long seconds = timestamp.getSeconds();
+ int nanos = timestamp.getNanos();
+ checkValid(seconds, nanos);
+ StringBuilder result = new StringBuilder();
+ // Format the seconds part.
+ Date date = new Date(seconds * MILLIS_PER_SECOND);
+ 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 timestmap: timestamp is out of range.", 0);
+ }
+ }
+
+ /**
+ * 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) {
+ return 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 millisecond.
+ */
+ public static long toMicros(Timestamp timestamp) {
+ return 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) {
+ return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
+ }
+
+ /**
+ * Calculate the difference between two timestamps.
+ */
+ public static Duration between(Timestamp from, Timestamp to) {
+ return Durations.normalizedDuration(
+ to.getSeconds() - from.getSeconds(), to.getNanos() - from.getNanos());
+ }
+
+ /**
+ * Add a duration to a timestamp.
+ */
+ public static Timestamp add(Timestamp start, Duration length) {
+ return normalizedTimestamp(
+ start.getSeconds() + length.getSeconds(), start.getNanos() + length.getNanos());
+ }
+
+ /**
+ * Subtract a duration from a timestamp.
+ */
+ public static Timestamp subtract(Timestamp start, Duration length) {
+ return normalizedTimestamp(
+ start.getSeconds() - length.getSeconds(), start.getNanos() - length.getNanos());
+ }
+
+ 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;
+ }
+ checkValid(seconds, nanos);
+ return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+ }
+
+ 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 nanosecnds.", 0);
+ }
+ result += value.charAt(i) - '0';
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Format the nano part of a timestamp or a duration.
+ */
+ static String formatNanos(int nanos) {
+ assert nanos >= 1 && nanos <= 999999999;
+ // Determine whether to use 3, 6, or 9 digits for the nano part.
+ if (nanos % NANOS_PER_MILLISECOND == 0) {
+ return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);
+ } else if (nanos % NANOS_PER_MICROSECOND == 0) {
+ return String.format("%1$06d", nanos / NANOS_PER_MICROSECOND);
+ } else {
+ return String.format("%1$09d", nanos);
+ }
+ }
+}
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 194f7b9c..1a998570 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 class FieldMaskUtilTest extends TestCase {
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 @@ public class FieldMaskUtilTest extends TestCase {
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 @@ public class FieldMaskUtilTest extends TestCase {
} 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.
@@ -161,7 +189,7 @@ public class FieldMaskUtilTest extends TestCase {
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.
@@ -170,13 +198,14 @@ public class FieldMaskUtilTest extends TestCase {
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 d95b626c..4d9a417d 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
@@ -41,6 +41,7 @@ import com.google.protobuf.Int64Value;
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;
@@ -82,7 +83,7 @@ public class JsonFormatTest extends TestCase {
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 +101,7 @@ public class JsonFormatTest extends TestCase {
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,7 +119,7 @@ public class JsonFormatTest extends TestCase {
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);
}
@@ -198,20 +199,22 @@ public class JsonFormatTest extends TestCase {
}
public void testUnknownEnumValues() throws Exception {
- TestAllTypes message = TestAllTypes.newBuilder()
- .setOptionalNestedEnumValue(12345)
- .addRepeatedNestedEnumValue(12345)
- .addRepeatedNestedEnumValue(0)
- .build();
+ TestAllTypes message =
+ TestAllTypes.newBuilder()
+ .setOptionalNestedEnumValue(12345)
+ .addRepeatedNestedEnumValue(12345)
+ .addRepeatedNestedEnumValue(0)
+ .build();
assertEquals(
"{\n"
- + " \"optionalNestedEnum\": 12345,\n"
- + " \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
- + "}", toJsonString(message));
+ + " \"optionalNestedEnum\": 12345,\n"
+ + " \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+ + "}",
+ toJsonString(message));
assertRoundTripEquals(message);
TestMap.Builder mapBuilder = TestMap.newBuilder();
- mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
+ mapBuilder.putInt32ToEnumMapValue(1, 0);
mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
TestMap mapMessage = mapBuilder.build();
assertEquals(
@@ -226,19 +229,21 @@ public class JsonFormatTest extends TestCase {
}
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);
}
@@ -247,15 +252,16 @@ public class JsonFormatTest extends TestCase {
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());
@@ -276,8 +282,9 @@ public class JsonFormatTest extends TestCase {
+ " \"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());
@@ -366,51 +373,49 @@ public class JsonFormatTest extends TestCase {
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.
@@ -418,16 +423,21 @@ public class JsonFormatTest extends TestCase {
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
@@ -441,7 +451,8 @@ public class JsonFormatTest extends TestCase {
"{\n"
+ " \"optionalNestedMessage\": {},\n"
+ " \"optional_nested_message\": {}\n"
- + "}", builder);
+ + "}",
+ builder);
fail();
} catch (InvalidProtocolBufferException e) {
// Exception expected.
@@ -452,9 +463,10 @@ public class JsonFormatTest extends TestCase {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
mergeFromJson(
"{\n"
- + " \"repeatedNestedMessage\": [null, null],\n"
- + " \"repeated_nested_message\": [null, null]\n"
- + "}", builder);
+ + " \"repeatedNestedMessage\": [null, null],\n"
+ + " \"repeated_nested_message\": [null, null]\n"
+ + "}",
+ builder);
fail();
} catch (InvalidProtocolBufferException e) {
// Exception expected.
@@ -463,11 +475,7 @@ public class JsonFormatTest extends TestCase {
// Duplicated oneof fields.
try {
TestOneof.Builder builder = TestOneof.newBuilder();
- mergeFromJson(
- "{\n"
- + " \"oneofInt32\": 1,\n"
- + " \"oneof_int32\": 2\n"
- + "}", builder);
+ mergeFromJson("{\n" + " \"oneofInt32\": 1,\n" + " \"oneof_int32\": 2\n" + "}", builder);
fail();
} catch (InvalidProtocolBufferException e) {
// Exception expected.
@@ -476,143 +484,138 @@ public class JsonFormatTest extends TestCase {
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.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.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.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);
}
@@ -621,9 +624,10 @@ public class JsonFormatTest extends TestCase {
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.
@@ -633,9 +637,10 @@ public class JsonFormatTest extends TestCase {
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.
@@ -645,10 +650,7 @@ public class JsonFormatTest extends TestCase {
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());
@@ -669,16 +671,17 @@ public class JsonFormatTest extends TestCase {
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();
@@ -690,57 +693,52 @@ public class JsonFormatTest extends TestCase {
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();
+ TestDuration message =
+ TestDuration.newBuilder().setDurationValue(Durations.parse("12345s")).build();
- assertEquals(
- "{\n"
- + " \"durationValue\": \"12345s\"\n"
- + "}", toJsonString(message));
+ 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);
}
@@ -748,45 +746,39 @@ public class JsonFormatTest extends TestCase {
// 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();
@@ -794,10 +786,7 @@ public class JsonFormatTest extends TestCase {
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));
+ assertEquals("{\n" + " \"listValue\": [31831.125, null]\n" + "}", toJsonString(message));
assertRoundTripEquals(message);
}
@@ -813,158 +802,169 @@ public class JsonFormatTest extends TestCase {
// 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);
-
// 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);
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);
}
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.
@@ -976,9 +976,10 @@ public class JsonFormatTest extends TestCase {
TestAllTypes.Builder builder = TestAllTypes.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.
@@ -988,10 +989,7 @@ public class JsonFormatTest extends TestCase {
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.
@@ -1022,10 +1020,7 @@ public class JsonFormatTest extends TestCase {
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.
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 4c31b2b3..a41528ec 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
@@ -84,6 +84,7 @@ public class TimeUtilTest extends TestCase {
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 +103,8 @@ public class TimeUtilTest extends TestCase {
}
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 +113,26 @@ public class TimeUtilTest extends TestCase {
}
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 +147,8 @@ public class TimeUtilTest extends TestCase {
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 +157,14 @@ public class TimeUtilTest extends TestCase {
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 +280,7 @@ public class TimeUtilTest extends TestCase {
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 +289,16 @@ public class TimeUtilTest extends TestCase {
try {
// Value too large.
- Duration value = Duration.newBuilder()
- .setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
+ 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(1).setNanos(-1).build();
TimeUtil.toString(value);
Assert.fail("Exception is expected.");
} catch (IllegalArgumentException e) {
@@ -309,8 +307,7 @@ public class TimeUtilTest extends TestCase {
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) {
@@ -367,8 +364,7 @@ public class TimeUtilTest extends TestCase {
}
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 +374,7 @@ public class TimeUtilTest extends TestCase {
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 +398,7 @@ public class TimeUtilTest extends TestCase {
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 +455,28 @@ public class TimeUtilTest extends TestCase {
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 686edc42..4bf223f2 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
@@ -124,6 +124,7 @@ message TestOneof {
oneof oneof_field {
int32 oneof_int32 = 1;
TestAllTypes.NestedMessage oneof_nested_message = 2;
+ google.protobuf.NullValue oneof_null_value = 3;
}
}
diff --git a/js/binary/constants.js b/js/binary/constants.js
index 836216bf..ef5fecdd 100644
--- a/js/binary/constants.js
+++ b/js/binary/constants.js
@@ -141,8 +141,8 @@ jspb.ReaderFunction;
/**
* A writer function serializes a message to a BinaryWriter.
- * @typedef {!function(!jspb.Message, !jspb.BinaryWriter):void |
- * !function(!jspb.ConstBinaryMessage, !jspb.BinaryWriter):void}
+ * @typedef {function((!jspb.Message|!jspb.ConstBinaryMessage),
+ * !jspb.BinaryWriter):void}
*/
jspb.WriterFunction;
diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js
index d045e912..ac312648 100644
--- a/js/binary/decoder_test.js
+++ b/js/binary/decoder_test.js
@@ -147,9 +147,8 @@ function doTestSignedValue(readValue,
describe('binaryDecoderTest', function() {
/**
* Tests the decoder instance cache.
- * @suppress {visibility}
*/
- it('testInstanceCache', function() {
+ it('testInstanceCache', /** @suppress {visibility} */ function() {
// Empty the instance caches.
jspb.BinaryDecoder.instanceCache_ = [];
diff --git a/js/binary/reader_test.js b/js/binary/reader_test.js
index db674cf8..95711385 100644
--- a/js/binary/reader_test.js
+++ b/js/binary/reader_test.js
@@ -52,9 +52,8 @@ goog.require('jspb.BinaryWriter');
describe('binaryReaderTest', function() {
/**
* Tests the reader instance cache.
- * @suppress {visibility}
*/
- it('testInstanceCaches', function() {
+ it('testInstanceCaches', /** @suppress {visibility} */ function() {
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
writer.writeMessage(1, dummyMessage, goog.nullFunction);
@@ -131,9 +130,8 @@ describe('binaryReaderTest', function() {
/**
* Verifies that misuse of the reader class triggers assertions.
- * @suppress {checkTypes|visibility}
*/
- it('testReadErrors', function() {
+ it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() {
// Calling readMessage on a non-delimited field should trigger an
// assertion.
var reader = jspb.BinaryReader.alloc([8, 1]);
@@ -200,7 +198,7 @@ describe('binaryReaderTest', function() {
* @private
* @suppress {missingProperties}
*/
- function doTestUnsignedField_(readField,
+ var doTestUnsignedField_ = function(readField,
writeField, epsilon, upperLimit, filter) {
assertNotNull(readField);
assertNotNull(writeField);
@@ -252,7 +250,7 @@ describe('binaryReaderTest', function() {
* @private
* @suppress {missingProperties}
*/
- function doTestSignedField_(readField,
+ var doTestSignedField_ = function(readField,
writeField, epsilon, lowerLimit, upperLimit, filter) {
var writer = new jspb.BinaryWriter();
@@ -321,12 +319,12 @@ describe('binaryReaderTest', function() {
* Tests fields that use varint encoding.
*/
it('testVarintFields', function() {
- assertNotNull(jspb.BinaryReader.prototype.readUint32);
- assertNotNull(jspb.BinaryReader.prototype.writeUint32);
- assertNotNull(jspb.BinaryReader.prototype.readUint64);
- assertNotNull(jspb.BinaryReader.prototype.writeUint64);
- assertNotNull(jspb.BinaryReader.prototype.readBool);
- assertNotNull(jspb.BinaryReader.prototype.writeBool);
+ assertNotUndefined(jspb.BinaryReader.prototype.readUint32);
+ assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32);
+ assertNotUndefined(jspb.BinaryReader.prototype.readUint64);
+ assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64);
+ assertNotUndefined(jspb.BinaryReader.prototype.readBool);
+ assertNotUndefined(jspb.BinaryWriter.prototype.writeBool);
doTestUnsignedField_(
jspb.BinaryReader.prototype.readUint32,
jspb.BinaryWriter.prototype.writeUint32,
@@ -369,8 +367,7 @@ describe('binaryReaderTest', function() {
var bytesCount = (hexString.length + 1) / 3;
var bytes = new Uint8Array(bytesCount);
for (var i = 0; i < bytesCount; i++) {
- byte = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
- bytes[i] = byte;
+ bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
}
var reader = jspb.BinaryReader.alloc(bytes);
reader.nextField();
diff --git a/js/binary/writer.js b/js/binary/writer.js
index be4478ee..3eb2f1bd 100644
--- a/js/binary/writer.js
+++ b/js/binary/writer.js
@@ -717,11 +717,19 @@ jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
/**
* Writes a message to the buffer.
- * @template MessageType
* @param {number} field The field number.
* @param {?MessageType} value The message to write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- * to write and the writer to write it with.
+ * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
+ * Will be invoked with the value to write and the writer to write it with.
+ * @template MessageType
+ * Use go/closure-ttl to declare a non-nullable version of MessageType. Replace
+ * the null in blah|null with none. This is necessary because the compiler will
+ * infer MessageType to be nullable if the value parameter is nullable.
+ * @template MessageTypeNonNull :=
+ * cond(isUnknown(MessageType), unknown(),
+ * mapunion(MessageType, (X) =>
+ * cond(eq(X, 'null'), none(), X)))
+ * =:
*/
jspb.BinaryWriter.prototype.writeMessage = function(
field, value, writerCallback) {
@@ -735,12 +743,20 @@ jspb.BinaryWriter.prototype.writeMessage = function(
/**
* Writes a group message to the buffer.
*
- * @template MessageType
* @param {number} field The field number.
* @param {?MessageType} value The message to write, wrapped with START_GROUP /
* END_GROUP tags. Will be a no-op if 'value' is null.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- * to write and the writer to write it with.
+ * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
+ * Will be invoked with the value to write and the writer to write it with.
+ * @template MessageType
+ * Use go/closure-ttl to declare a non-nullable version of MessageType. Replace
+ * the null in blah|null with none. This is necessary because the compiler will
+ * infer MessageType to be nullable if the value parameter is nullable.
+ * @template MessageTypeNonNull :=
+ * cond(isUnknown(MessageType), unknown(),
+ * mapunion(MessageType, (X) =>
+ * cond(eq(X, 'null'), none(), X)))
+ * =:
*/
jspb.BinaryWriter.prototype.writeGroup = function(
field, value, writerCallback) {
@@ -1122,8 +1138,8 @@ jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
* @param {number} field The field number.
* @param {?Array.<MessageType>} value The array of messages to
* write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- * to write and the writer to write it with.
+ * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
+ * Will be invoked with the value to write and the writer to write it with.
*/
jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
field, value, writerCallback) {
@@ -1142,8 +1158,8 @@ jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
* @param {number} field The field number.
* @param {?Array.<MessageType>} value The array of messages to
* write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- * to write and the writer to write it with.
+ * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
+ * Will be invoked with the value to write and the writer to write it with.
*/
jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
field, value, writerCallback) {
diff --git a/js/message.js b/js/message.js
index 813e6b8c..3863bac0 100644
--- a/js/message.js
+++ b/js/message.js
@@ -41,6 +41,7 @@ goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.crypt.base64');
goog.require('goog.json');
+goog.require('jspb.Map');
// Not needed in compilation units that have no protos with xids.
goog.forwardDeclare('xid.String');
@@ -371,7 +372,8 @@ jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) {
// the object is not an array, since arrays are valid field values.
// NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
// in Safari on iOS 8. See the description of CL/86511464 for details.
- if (obj && typeof obj == 'object' && !goog.isArray(obj)) {
+ if (obj && typeof obj == 'object' && !goog.isArray(obj) &&
+ !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
msg.extensionObject_ = obj;
return;
@@ -738,6 +740,62 @@ jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
/**
+ * Gets the value of a map field, lazily creating the map container if
+ * necessary.
+ *
+ * This should only be called from generated code, because it requires knowledge
+ * of serialization/parsing callbacks (which are required by the map at
+ * construction time, and the map may be constructed here).
+ *
+ * The below callbacks are used to allow the map to serialize and parse its
+ * binary wire format data. Their purposes are described in more detail in
+ * `jspb.Map`'s constructor documentation.
+ *
+ * @template K, V
+ * @param {!jspb.Message} msg
+ * @param {number} fieldNumber
+ * @param {boolean|undefined} noLazyCreate
+ * @param {?=} opt_valueCtor
+ * @param {function(number,K)=} opt_keyWriterFn
+ * @param {function():K=} opt_keyReaderFn
+ * @param {function(number,V)|function(number,V,?)|
+ * function(number,V,?,?,?,?)=} opt_valueWriterFn
+ * @param {function():V|
+ * function(V,function(?,?))=} opt_valueReaderFn
+ * @param {function(?,?)|function(?,?,?,?,?)=} opt_valueWriterCallback
+ * @param {function(?,?)=} opt_valueReaderCallback
+ * @return {!jspb.Map<K, V>|undefined}
+ * @protected
+ */
+jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
+ opt_valueCtor, opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
+ opt_valueReaderFn, opt_valueWriterCallback, opt_valueReaderCallback) {
+ if (!msg.wrappers_) {
+ msg.wrappers_ = {};
+ }
+ // If we already have a map in the map wrappers, return that.
+ if (fieldNumber in msg.wrappers_) {
+ return msg.wrappers_[fieldNumber];
+ } else if (noLazyCreate) {
+ return undefined;
+ } else {
+ // Wrap the underlying elements array with a Map.
+ var arr = jspb.Message.getField(msg, fieldNumber);
+ if (!arr) {
+ arr = [];
+ jspb.Message.setField(msg, fieldNumber, arr);
+ }
+ return msg.wrappers_[fieldNumber] =
+ new jspb.Map(
+ /** @type {!Array<!Array<!Object>>} */ (arr),
+ opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
+ opt_valueReaderFn, opt_valueCtor, opt_valueWriterCallback,
+ opt_valueReaderCallback);
+ }
+};
+
+
+/**
* Sets the value of a non-extension field.
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
@@ -953,12 +1011,45 @@ jspb.Message.toMap = function(
/**
+ * Syncs all map fields' contents back to their underlying arrays.
+ * @private
+ */
+jspb.Message.prototype.syncMapFields_ = function() {
+ // This iterates over submessage, map, and repeated fields, which is intended.
+ // Submessages can contain maps which also need to be synced.
+ //
+ // There is a lot of opportunity for optimization here. For example we could
+ // statically determine that some messages have no submessages with maps and
+ // optimize this method away for those just by generating one extra static
+ // boolean per message type.
+ if (this.wrappers_) {
+ for (var fieldNumber in this.wrappers_) {
+ var val = this.wrappers_[fieldNumber];
+ if (goog.isArray(val)) {
+ for (var i = 0; i < val.length; i++) {
+ if (val[i]) {
+ val[i].toArray();
+ }
+ }
+ } else {
+ // Works for submessages and maps.
+ if (val) {
+ val.toArray();
+ }
+ }
+ }
+ }
+};
+
+
+/**
* Returns the internal array of this proto.
* <p>Note: If you use this array to construct a second proto, the content
* would then be partially shared between the two protos.
* @return {!Array} The proto represented as an array.
*/
jspb.Message.prototype.toArray = function() {
+ this.syncMapFields_();
return this.array;
};
@@ -972,6 +1063,7 @@ jspb.Message.prototype.toArray = function() {
* @override
*/
jspb.Message.prototype.toString = function() {
+ this.syncMapFields_();
return this.array.toString();
};
@@ -1293,6 +1385,9 @@ jspb.Message.clone_ = function(obj) {
}
return clonedArray;
}
+ if (jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array) {
+ return new Uint8Array(obj);
+ }
var clone = {};
for (var key in obj) {
if ((o = obj[key]) != null) {
diff --git a/js/message_test.js b/js/message_test.js
index 01add5f1..0b0c0172 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -34,6 +34,7 @@ goog.setTestOnly();
goog.require('goog.json');
goog.require('goog.testing.asserts');
+goog.require('goog.userAgent');
// CommonJS-LoadFromFile: google-protobuf jspb
goog.require('jspb.Message');
@@ -66,6 +67,7 @@ goog.require('proto.jspb.test.Simple1');
goog.require('proto.jspb.test.Simple2');
goog.require('proto.jspb.test.SpecialCases');
goog.require('proto.jspb.test.TestClone');
+goog.require('proto.jspb.test.TestEndsWithBytes');
goog.require('proto.jspb.test.TestGroup');
goog.require('proto.jspb.test.TestGroup1');
goog.require('proto.jspb.test.TestMessageWithOneof');
@@ -438,6 +440,8 @@ describe('Message test suite', function() {
});
it('testClone', function() {
+ var supportsUint8Array =
+ !goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10');
var original = new proto.jspb.test.TestClone();
original.setStr('v1');
var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
@@ -445,12 +449,14 @@ describe('Message test suite', function() {
var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
original.setSimple1(simple1);
original.setSimple2List([simple2, simple3]);
+ var bytes1 = supportsUint8Array ? new Uint8Array([1, 2, 3]) : '123';
+ original.setBytesField(bytes1);
var extension = new proto.jspb.test.CloneExtension();
extension.setExt('e1');
original.setExtension(proto.jspb.test.IsExtension.extField, extension);
var clone = original.cloneMessage();
assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
- [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+ [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
clone.toArray());
clone.setStr('v2');
var simple4 = new proto.jspb.test.Simple1(['a1', ['b1', 'c1']]);
@@ -458,18 +464,26 @@ describe('Message test suite', function() {
var simple6 = new proto.jspb.test.Simple1(['a3', ['b3', 'c3']]);
clone.setSimple1(simple4);
clone.setSimple2List([simple5, simple6]);
+ if (supportsUint8Array) {
+ clone.getBytesField()[0] = 4;
+ assertObjectEquals(bytes1, original.getBytesField());
+ }
+ var bytes2 = supportsUint8Array ? new Uint8Array([4, 5, 6]) : '456';
+ clone.setBytesField(bytes2);
var newExtension = new proto.jspb.test.CloneExtension();
newExtension.setExt('e2');
clone.setExtension(proto.jspb.test.CloneExtension.extField, newExtension);
assertArrayEquals(['v2',, ['a1', ['b1', 'c1']],,
- [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]],,, { 100: [, 'e2'] }],
+ [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]], bytes2,, { 100: [, 'e2'] }],
clone.toArray());
assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
- [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+ [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
original.toArray());
});
it('testCopyInto', function() {
+ var supportsUint8Array =
+ !goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10');
var original = new proto.jspb.test.TestClone();
original.setStr('v1');
var dest = new proto.jspb.test.TestClone();
@@ -484,6 +498,10 @@ describe('Message test suite', function() {
original.setSimple2List([simple2, simple3]);
dest.setSimple1(destSimple1);
dest.setSimple2List([destSimple2, destSimple3]);
+ var bytes1 = supportsUint8Array ? new Uint8Array([1, 2, 3]) : '123';
+ var bytes2 = supportsUint8Array ? new Uint8Array([4, 5, 6]) : '456';
+ original.setBytesField(bytes1);
+ dest.setBytesField(bytes2);
var extension = new proto.jspb.test.CloneExtension();
extension.setExt('e1');
original.setExtension(proto.jspb.test.CloneExtension.extField, extension);
@@ -496,6 +514,15 @@ describe('Message test suite', function() {
dest.getSimple1().setAString('new value');
assertNotEquals(dest.getSimple1().getAString(),
original.getSimple1().getAString());
+ if (supportsUint8Array) {
+ dest.getBytesField()[0] = 7;
+ assertObjectEquals(bytes1, original.getBytesField());
+ assertObjectEquals(new Uint8Array([7, 2, 3]), dest.getBytesField());
+ } else {
+ dest.setBytesField('789');
+ assertObjectEquals(bytes1, original.getBytesField());
+ assertObjectEquals('789', dest.getBytesField());
+ }
dest.getExtension(proto.jspb.test.CloneExtension.extField).
setExt('new value');
assertNotEquals(
diff --git a/js/test.proto b/js/test.proto
index 6b9dc891..06eb79af 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -160,6 +160,7 @@ message TestClone {
optional string str = 1;
optional Simple1 simple1 = 3;
repeated Simple1 simple2 = 5;
+ optional bytes bytes_field = 6;
optional string unused = 7;
extensions 10 to max;
}
diff --git a/js/testbinary.proto b/js/testbinary.proto
index 60c70190..a3fcb5f1 100644
--- a/js/testbinary.proto
+++ b/js/testbinary.proto
@@ -183,3 +183,32 @@ extend TestExtendable {
[packed=true];
}
+
+message TestMapFields {
+ option (jspb.generate_from_object) = true;
+
+ map<string, string> map_string_string = 1;
+ map<string, int32> map_string_int32 = 2;
+ map<string, int64> map_string_int64 = 3;
+ map<string, bool> map_string_bool = 4;
+ map<string, double> map_string_double = 5;
+ map<string, MapValueEnum> map_string_enum = 6;
+ map<string, MapValueMessage> map_string_msg = 7;
+
+ map<int32, string> map_int32_string = 8;
+ map<int64, string> map_int64_string = 9;
+ map<bool, string> map_bool_string = 10;
+
+ optional TestMapFields test_map_fields = 11;
+ map<string, TestMapFields> map_string_testmapfields = 12;
+}
+
+enum MapValueEnum {
+ MAP_VALUE_FOO = 0;
+ MAP_VALUE_BAR = 1;
+ MAP_VALUE_BAZ = 2;
+}
+
+message MapValueMessage {
+ optional int32 foo = 1;
+}
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 3209b34d..2eba1232 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -258,7 +258,7 @@ class Descriptor(_NestedDescriptorBase):
def __new__(cls, name, full_name, filename, containing_type, fields,
nested_types, enum_types, extensions, options=None,
is_extendable=True, extension_ranges=None, oneofs=None,
- file=None, serialized_start=None, serialized_end=None,
+ file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin
syntax=None):
_message.Message._CheckCalledFromGeneratedFile()
return _message.default_pool.FindMessageTypeByName(full_name)
@@ -269,8 +269,8 @@ class Descriptor(_NestedDescriptorBase):
def __init__(self, name, full_name, filename, containing_type, fields,
nested_types, enum_types, extensions, options=None,
is_extendable=True, extension_ranges=None, oneofs=None,
- file=None, serialized_start=None, serialized_end=None,
- syntax=None): # pylint:disable=redefined-builtin
+ file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin
+ syntax=None):
"""Arguments to __init__() are as described in the description
of Descriptor fields above.
@@ -665,7 +665,7 @@ class EnumValueDescriptor(DescriptorBase):
self.type = type
-class OneofDescriptor(object):
+class OneofDescriptor(DescriptorBase):
"""Descriptor for a oneof field.
name: (str) Name of the oneof field.
@@ -682,12 +682,15 @@ class OneofDescriptor(object):
if _USE_C_DESCRIPTORS:
_C_DESCRIPTOR_CLASS = _message.OneofDescriptor
- def __new__(cls, name, full_name, index, containing_type, fields):
+ def __new__(
+ cls, name, full_name, index, containing_type, fields, options=None):
_message.Message._CheckCalledFromGeneratedFile()
return _message.default_pool.FindOneofByName(full_name)
- def __init__(self, name, full_name, index, containing_type, fields):
+ def __init__(
+ self, name, full_name, index, containing_type, fields, options=None):
"""Arguments are as described in the attribute description above."""
+ super(OneofDescriptor, self).__init__(options, 'OneofOptions')
self.name = name
self.full_name = full_name
self.index = index
@@ -705,11 +708,22 @@ class ServiceDescriptor(_NestedDescriptorBase):
definition appears withing the .proto file.
methods: (list of MethodDescriptor) List of methods provided by this
service.
+ methods_by_name: (dict str -> MethodDescriptor) Same MethodDescriptor
+ objects as in |methods_by_name|, but indexed by "name" attribute in each
+ MethodDescriptor.
options: (descriptor_pb2.ServiceOptions) Service options message or
None to use default service options.
file: (FileDescriptor) Reference to file info.
"""
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
+
+ def __new__(cls, name, full_name, index, methods, options=None, file=None, # pylint: disable=redefined-builtin
+ serialized_start=None, serialized_end=None):
+ _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access
+ return _message.default_pool.FindServiceByName(full_name)
+
def __init__(self, name, full_name, index, methods, options=None, file=None,
serialized_start=None, serialized_end=None):
super(ServiceDescriptor, self).__init__(
@@ -718,16 +732,14 @@ class ServiceDescriptor(_NestedDescriptorBase):
serialized_end=serialized_end)
self.index = index
self.methods = methods
+ self.methods_by_name = dict((m.name, m) for m in methods)
# Set the containing service for each method in this service.
for method in self.methods:
method.containing_service = self
def FindMethodByName(self, name):
"""Searches for the specified method, and returns its descriptor."""
- for method in self.methods:
- if name == method.name:
- return method
- return None
+ return self.methods_by_name.get(name, None)
def CopyToProto(self, proto):
"""Copies this to a descriptor_pb2.ServiceDescriptorProto.
@@ -754,6 +766,14 @@ class MethodDescriptor(DescriptorBase):
None to use default method options.
"""
+ if _USE_C_DESCRIPTORS:
+ _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
+
+ def __new__(cls, name, full_name, index, containing_service,
+ input_type, output_type, options=None):
+ _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access
+ return _message.default_pool.FindMethodByName(full_name)
+
def __init__(self, name, full_name, index, containing_service,
input_type, output_type, options=None):
"""The arguments are as described in the description of MethodDescriptor
@@ -788,6 +808,7 @@ class FileDescriptor(DescriptorBase):
message_types_by_name: Dict of message names of their descriptors.
enum_types_by_name: Dict of enum names and their descriptors.
extensions_by_name: Dict of extension names and their descriptors.
+ services_by_name: Dict of services names and their descriptors.
pool: the DescriptorPool this descriptor belongs to. When not passed to the
constructor, the global default pool is used.
"""
@@ -825,6 +846,7 @@ class FileDescriptor(DescriptorBase):
self.enum_types_by_name = {}
self.extensions_by_name = {}
+ self.services_by_name = {}
self.dependencies = (dependencies or [])
self.public_dependencies = (public_dependencies or [])
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 20a33701..5c055ab9 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -394,6 +394,11 @@ class DescriptorPool(object):
desc_proto_prefix, desc_proto.name, scope)
file_descriptor.message_types_by_name[desc_proto.name] = desc
+ for index, service_proto in enumerate(file_proto.service):
+ file_descriptor.services_by_name[service_proto.name] = (
+ self._MakeServiceDescriptor(service_proto, index, scope,
+ file_proto.package, file_descriptor))
+
self.Add(file_proto)
self._file_descriptors[file_proto.name] = file_descriptor
@@ -441,7 +446,7 @@ class DescriptorPool(object):
for index, extension in enumerate(desc_proto.extension)]
oneofs = [
descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
- index, None, [])
+ index, None, [], desc.options)
for index, desc in enumerate(desc_proto.oneof_decl)]
extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
if extension_ranges:
@@ -679,6 +684,64 @@ class DescriptorPool(object):
options=value_proto.options,
type=None)
+ def _MakeServiceDescriptor(self, service_proto, service_index, scope,
+ package, file_desc):
+ """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto.
+
+ Args:
+ service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message.
+ service_index: The index of the service in the File.
+ scope: Dict mapping short and full symbols to message and enum types.
+ package: Optional package name for the new message EnumDescriptor.
+ file_desc: The file containing the service descriptor.
+
+ Returns:
+ The added descriptor.
+ """
+
+ if package:
+ service_name = '.'.join((package, service_proto.name))
+ else:
+ service_name = service_proto.name
+
+ methods = [self._MakeMethodDescriptor(method_proto, service_name, package,
+ scope, index)
+ for index, method_proto in enumerate(service_proto.method)]
+ desc = descriptor.ServiceDescriptor(name=service_proto.name,
+ full_name=service_name,
+ index=service_index,
+ methods=methods,
+ options=service_proto.options,
+ file=file_desc)
+ return desc
+
+ def _MakeMethodDescriptor(self, method_proto, service_name, package, scope,
+ index):
+ """Creates a method descriptor from a MethodDescriptorProto.
+
+ Args:
+ method_proto: The proto describing the method.
+ service_name: The name of the containing service.
+ package: Optional package name to look up for types.
+ scope: Scope containing available types.
+ index: Index of the method in the service.
+
+ Returns:
+ An initialized MethodDescriptor object.
+ """
+ full_name = '.'.join((service_name, method_proto.name))
+ input_type = self._GetTypeFromScope(
+ package, method_proto.input_type, scope)
+ output_type = self._GetTypeFromScope(
+ package, method_proto.output_type, scope)
+ return descriptor.MethodDescriptor(name=method_proto.name,
+ full_name=full_name,
+ index=index,
+ containing_service=None,
+ input_type=input_type,
+ output_type=output_type,
+ options=method_proto.options)
+
def _ExtractSymbols(self, descriptors):
"""Pulls out all the symbols from descriptor protos.
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index 97cdd848..ce46d08c 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -594,7 +594,11 @@ class MessageMap(MutableMapping):
def MergeFrom(self, other):
for key in other:
- self[key].MergeFrom(other[key])
+ # According to documentation: "When parsing from the wire or when merging,
+ # if there are duplicate map keys the last key seen is used".
+ if key in self:
+ del self[key]
+ self[key].CopyFrom(other[key])
# self._message_listener.Modified() not required here, because
# mutations to submessages already propagate.
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 6a13e0bc..3c8c7935 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -51,6 +51,7 @@ from google.protobuf.internal import descriptor_pool_test1_pb2
from google.protobuf.internal import descriptor_pool_test2_pb2
from google.protobuf.internal import factory_test1_pb2
from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import file_options_test_pb2
from google.protobuf.internal import more_messages_pb2
from google.protobuf import descriptor
from google.protobuf import descriptor_database
@@ -630,6 +631,23 @@ class AddDescriptorTest(unittest.TestCase):
self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
'Message')
+ def testFileDescriptorOptionsWithCustomDescriptorPool(self):
+ # Create a descriptor pool, and add a new FileDescriptorProto to it.
+ pool = descriptor_pool.DescriptorPool()
+ file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto'
+ file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name)
+ extension_id = file_options_test_pb2.foo_options
+ file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo'
+ pool.Add(file_descriptor_proto)
+ # The options set on the FileDescriptorProto should be available in the
+ # descriptor even if they contain extensions that cannot be deserialized
+ # using the pool.
+ file_descriptor = pool.FindFileByName(file_name)
+ options = file_descriptor.GetOptions()
+ self.assertEqual('foo', options.Extensions[extension_id].foo_name)
+ # The object returned by GetOptions() is cached.
+ self.assertIs(options, file_descriptor.GetOptions())
+
@unittest.skipIf(
api_implementation.Type() != 'cpp',
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index b8e75553..623198c8 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -77,27 +77,24 @@ class DescriptorTest(unittest.TestCase):
enum_proto.value.add(name='FOREIGN_BAR', number=5)
enum_proto.value.add(name='FOREIGN_BAZ', number=6)
+ file_proto.message_type.add(name='ResponseMessage')
+ service_proto = file_proto.service.add(
+ name='Service')
+ method_proto = service_proto.method.add(
+ name='CallMethod',
+ input_type='.protobuf_unittest.NestedMessage',
+ output_type='.protobuf_unittest.ResponseMessage')
+
+ # Note: Calling DescriptorPool.Add() multiple times with the same file only
+ # works if the input is canonical; in particular, all type names must be
+ # fully qualified.
self.pool = self.GetDescriptorPool()
self.pool.Add(file_proto)
self.my_file = self.pool.FindFileByName(file_proto.name)
self.my_message = self.my_file.message_types_by_name[message_proto.name]
self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
-
- self.my_method = descriptor.MethodDescriptor(
- name='Bar',
- full_name='protobuf_unittest.TestService.Bar',
- index=0,
- containing_service=None,
- input_type=None,
- output_type=None)
- self.my_service = descriptor.ServiceDescriptor(
- name='TestServiceWithOptions',
- full_name='protobuf_unittest.TestServiceWithOptions',
- file=self.my_file,
- index=0,
- methods=[
- self.my_method
- ])
+ self.my_service = self.my_file.services_by_name[service_proto.name]
+ self.my_method = self.my_service.methods_by_name[method_proto.name]
def GetDescriptorPool(self):
return symbol_database.Default().pool
@@ -139,13 +136,14 @@ class DescriptorTest(unittest.TestCase):
file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
message_descriptor =\
unittest_custom_options_pb2.TestMessageWithCustomOptions.DESCRIPTOR
- field_descriptor = message_descriptor.fields_by_name["field1"]
- enum_descriptor = message_descriptor.enum_types_by_name["AnEnum"]
+ field_descriptor = message_descriptor.fields_by_name['field1']
+ oneof_descriptor = message_descriptor.oneofs_by_name['AnOneof']
+ enum_descriptor = message_descriptor.enum_types_by_name['AnEnum']
enum_value_descriptor =\
- message_descriptor.enum_values_by_name["ANENUM_VAL2"]
+ message_descriptor.enum_values_by_name['ANENUM_VAL2']
service_descriptor =\
unittest_custom_options_pb2.TestServiceWithCustomOptions.DESCRIPTOR
- method_descriptor = service_descriptor.FindMethodByName("Foo")
+ method_descriptor = service_descriptor.FindMethodByName('Foo')
file_options = file_descriptor.GetOptions()
file_opt1 = unittest_custom_options_pb2.file_opt1
@@ -158,6 +156,9 @@ class DescriptorTest(unittest.TestCase):
self.assertEqual(8765432109, field_options.Extensions[field_opt1])
field_opt2 = unittest_custom_options_pb2.field_opt2
self.assertEqual(42, field_options.Extensions[field_opt2])
+ oneof_options = oneof_descriptor.GetOptions()
+ oneof_opt1 = unittest_custom_options_pb2.oneof_opt1
+ self.assertEqual(-99, oneof_options.Extensions[oneof_opt1])
enum_options = enum_descriptor.GetOptions()
enum_opt1 = unittest_custom_options_pb2.enum_opt1
self.assertEqual(-789, enum_options.Extensions[enum_opt1])
diff --git a/python/google/protobuf/internal/file_options_test.proto b/python/google/protobuf/internal/file_options_test.proto
new file mode 100644
index 00000000..4eceeb07
--- /dev/null
+++ b/python/google/protobuf/internal/file_options_test.proto
@@ -0,0 +1,43 @@
+// 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 = "proto2";
+
+import "google/protobuf/descriptor.proto";
+
+package google.protobuf.python.internal;
+
+message FooOptions {
+ optional string foo_name = 1;
+}
+
+extend .google.protobuf.FileOptions {
+ optional FooOptions foo_options = 120436268;
+}
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 9e32ea47..6df12bea 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -643,6 +643,19 @@ class JsonFormatTest(JsonFormatBase):
'Message type "proto3.TestMessage" has no field named '
'"unknownName".')
+ def testIgnoreUnknownField(self):
+ text = '{"unknownName": 1}'
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+ text = ('{\n'
+ ' "repeatedValue": [ {\n'
+ ' "@type": "type.googleapis.com/proto3.MessageType",\n'
+ ' "unknownName": 1\n'
+ ' }]\n'
+ '}\n')
+ parsed_message = json_format_proto3_pb2.TestAny()
+ json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+
def testDuplicateField(self):
# Duplicate key check is not supported for python2.6
if sys.version_info < (2, 7):
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 4ee31d8e..1e95adf9 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -1435,6 +1435,8 @@ class Proto3Test(unittest.TestCase):
msg2.map_int32_int32[12] = 55
msg2.map_int64_int64[88] = 99
msg2.map_int32_foreign_message[222].c = 15
+ msg2.map_int32_foreign_message[222].d = 20
+ old_map_value = msg2.map_int32_foreign_message[222]
msg2.MergeFrom(msg)
@@ -1444,6 +1446,8 @@ class Proto3Test(unittest.TestCase):
self.assertEqual(99, msg2.map_int64_int64[88])
self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
+ self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
+ self.assertEqual(15, old_map_value.c)
# Verify that there is only one entry per key, even though the MergeFrom
# may have internally created multiple entries for a single key in the
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index ab2bf05b..0e38e0e9 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -40,12 +40,13 @@ import six
import string
try:
- import unittest2 as unittest #PY26
+ import unittest2 as unittest # PY26, pylint: disable=g-import-not-at-top
except ImportError:
- import unittest
+ import unittest # pylint: disable=g-import-not-at-top
from google.protobuf.internal import _parameterized
+from google.protobuf import any_test_pb2
from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
@@ -53,6 +54,7 @@ from google.protobuf import unittest_proto3_arena_pb2
from google.protobuf.internal import api_implementation
from google.protobuf.internal import test_util
from google.protobuf.internal import message_set_extensions_pb2
+from google.protobuf import descriptor_pool
from google.protobuf import text_format
@@ -90,13 +92,11 @@ class TextFormatBase(unittest.TestCase):
.replace('e-0','e-').replace('e-0','e-')
# Floating point fields are printed with .0 suffix even if they are
# actualy integer numbers.
- text = re.compile('\.0$', re.MULTILINE).sub('', text)
+ text = re.compile(r'\.0$', re.MULTILINE).sub('', text)
return text
-@_parameterized.Parameters(
- (unittest_pb2),
- (unittest_proto3_arena_pb2))
+@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
class TextFormatTest(TextFormatBase):
def testPrintExotic(self, message_module):
@@ -120,8 +120,10 @@ class TextFormatTest(TextFormatBase):
'repeated_string: "\\303\\274\\352\\234\\237"\n')
def testPrintExoticUnicodeSubclass(self, message_module):
+
class UnicodeSub(six.text_type):
pass
+
message = message_module.TestAllTypes()
message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
self.CompareToGoldenText(
@@ -165,8 +167,8 @@ class TextFormatTest(TextFormatBase):
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
message.repeated_string.append(u'\u00fc\ua71f')
self.CompareToGoldenText(
- self.RemoveRedundantZeros(
- text_format.MessageToString(message, as_one_line=True)),
+ self.RemoveRedundantZeros(text_format.MessageToString(
+ message, as_one_line=True)),
'repeated_int64: -9223372036854775808'
' repeated_uint64: 18446744073709551615'
' repeated_double: 123.456'
@@ -187,21 +189,23 @@ class TextFormatTest(TextFormatBase):
message.repeated_string.append(u'\u00fc\ua71f')
# Test as_utf8 = False.
- wire_text = text_format.MessageToString(
- message, as_one_line=True, as_utf8=False)
+ wire_text = text_format.MessageToString(message,
+ as_one_line=True,
+ as_utf8=False)
parsed_message = message_module.TestAllTypes()
r = text_format.Parse(wire_text, parsed_message)
self.assertIs(r, parsed_message)
self.assertEqual(message, parsed_message)
# Test as_utf8 = True.
- wire_text = text_format.MessageToString(
- message, as_one_line=True, as_utf8=True)
+ wire_text = text_format.MessageToString(message,
+ as_one_line=True,
+ as_utf8=True)
parsed_message = message_module.TestAllTypes()
r = text_format.Parse(wire_text, parsed_message)
self.assertIs(r, parsed_message)
self.assertEqual(message, parsed_message,
- '\n%s != %s' % (message, parsed_message))
+ '\n%s != %s' % (message, parsed_message))
def testPrintRawUtf8String(self, message_module):
message = message_module.TestAllTypes()
@@ -211,7 +215,7 @@ class TextFormatTest(TextFormatBase):
parsed_message = message_module.TestAllTypes()
text_format.Parse(text, parsed_message)
self.assertEqual(message, parsed_message,
- '\n%s != %s' % (message, parsed_message))
+ '\n%s != %s' % (message, parsed_message))
def testPrintFloatFormat(self, message_module):
# Check that float_format argument is passed to sub-message formatting.
@@ -232,14 +236,15 @@ class TextFormatTest(TextFormatBase):
message.payload.repeated_double.append(.000078900)
formatted_fields = ['optional_float: 1.25',
'optional_double: -3.45678901234568e-6',
- 'repeated_float: -5642',
- 'repeated_double: 7.89e-5']
+ 'repeated_float: -5642', 'repeated_double: 7.89e-5']
text_message = text_format.MessageToString(message, float_format='.15g')
self.CompareToGoldenText(
self.RemoveRedundantZeros(text_message),
- 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(*formatted_fields))
+ 'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(
+ *formatted_fields))
# as_one_line=True is a separate code branch where float_format is passed.
- text_message = text_format.MessageToString(message, as_one_line=True,
+ text_message = text_format.MessageToString(message,
+ as_one_line=True,
float_format='.15g')
self.CompareToGoldenText(
self.RemoveRedundantZeros(text_message),
@@ -311,8 +316,7 @@ class TextFormatTest(TextFormatBase):
self.assertEqual(123.456, message.repeated_double[0])
self.assertEqual(1.23e22, message.repeated_double[1])
self.assertEqual(1.23e-18, message.repeated_double[2])
- self.assertEqual(
- '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
+ self.assertEqual('\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
self.assertEqual('foocorgegrault', message.repeated_string[1])
self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
self.assertEqual(u'\u00fc', message.repeated_string[3])
@@ -371,45 +375,38 @@ class TextFormatTest(TextFormatBase):
def testParseSingleWord(self, message_module):
message = message_module.TestAllTypes()
text = 'foo'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
- r'"foo".'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+ r'"foo".'), text_format.Parse, text, message)
def testParseUnknownField(self, message_module):
message = message_module.TestAllTypes()
text = 'unknown_field: 8\n'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
- r'"unknown_field".'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+ r'"unknown_field".'), text_format.Parse, text, message)
def testParseBadEnumValue(self, message_module):
message = message_module.TestAllTypes()
text = 'optional_nested_enum: BARR'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
- r'has no value named BARR.'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError,
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+ r'has no value named BARR.'), text_format.Parse,
+ text, message)
message = message_module.TestAllTypes()
text = 'optional_nested_enum: 100'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
- r'has no value with number 100.'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError,
+ (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+ r'has no value with number 100.'), text_format.Parse,
+ text, message)
def testParseBadIntValue(self, message_module):
message = message_module.TestAllTypes()
text = 'optional_int32: bork'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- ('1:17 : Couldn\'t parse integer: bork'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError,
+ ('1:17 : Couldn\'t parse integer: bork'),
+ text_format.Parse, text, message)
def testParseStringFieldUnescape(self, message_module):
message = message_module.TestAllTypes()
@@ -419,6 +416,7 @@ class TextFormatTest(TextFormatBase):
repeated_string: "\\\\xf\\\\x62"
repeated_string: "\\\\\xf\\\\\x62"
repeated_string: "\x5cx20"'''
+
text_format.Parse(text, message)
SLASH = '\\'
@@ -433,8 +431,7 @@ class TextFormatTest(TextFormatBase):
def testMergeDuplicateScalars(self, message_module):
message = message_module.TestAllTypes()
- text = ('optional_int32: 42 '
- 'optional_int32: 67')
+ text = ('optional_int32: 42 ' 'optional_int32: 67')
r = text_format.Merge(text, message)
self.assertIs(r, message)
self.assertEqual(67, message.optional_int32)
@@ -455,13 +452,11 @@ class TextFormatTest(TextFormatBase):
self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
def testParseMultipleOneof(self, message_module):
- m_string = '\n'.join([
- 'oneof_uint32: 11',
- 'oneof_string: "foo"'])
+ m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
m2 = message_module.TestAllTypes()
if message_module is unittest_pb2:
- with self.assertRaisesRegexp(
- text_format.ParseError, ' is specified along with field '):
+ with self.assertRaisesRegexp(text_format.ParseError,
+ ' is specified along with field '):
text_format.Parse(m_string, m2)
else:
text_format.Parse(m_string, m2)
@@ -477,8 +472,8 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
self.CompareToGoldenFile(
- self.RemoveRedundantZeros(
- text_format.MessageToString(message, pointy_brackets=True)),
+ self.RemoveRedundantZeros(text_format.MessageToString(
+ message, pointy_brackets=True)),
'text_format_unittest_data_pointy_oneof.txt')
def testParseGolden(self):
@@ -499,14 +494,6 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
self.RemoveRedundantZeros(text_format.MessageToString(message)),
'text_format_unittest_data_oneof_implemented.txt')
- def testPrintAllFieldsPointy(self):
- message = unittest_pb2.TestAllTypes()
- test_util.SetAllFields(message)
- self.CompareToGoldenFile(
- self.RemoveRedundantZeros(
- text_format.MessageToString(message, pointy_brackets=True)),
- 'text_format_unittest_data_pointy_oneof.txt')
-
def testPrintInIndexOrder(self):
message = unittest_pb2.TestFieldOrderings()
message.my_string = '115'
@@ -520,8 +507,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n'
'optional_nested_message {\n oo: 0\n bb: 1\n}\n')
self.CompareToGoldenText(
- self.RemoveRedundantZeros(text_format.MessageToString(
- message)),
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n'
'optional_nested_message {\n bb: 1\n oo: 0\n}\n')
@@ -552,14 +538,13 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
message.map_int64_int64[-2**33] = -2**34
message.map_uint32_uint32[123] = 456
message.map_uint64_uint64[2**33] = 2**34
- message.map_string_string["abc"] = "123"
+ message.map_string_string['abc'] = '123'
message.map_int32_foreign_message[111].c = 5
# Maps are serialized to text format using their underlying repeated
# representation.
self.CompareToGoldenText(
- text_format.MessageToString(message),
- 'map_int32_int32 {\n'
+ text_format.MessageToString(message), 'map_int32_int32 {\n'
' key: -123\n'
' value: -456\n'
'}\n'
@@ -592,9 +577,8 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
message.map_string_string[letter] = 'dummy'
for letter in reversed(string.ascii_uppercase[0:13]):
message.map_string_string[letter] = 'dummy'
- golden = ''.join((
- 'map_string_string {\n key: "%c"\n value: "dummy"\n}\n' % (letter,)
- for letter in string.ascii_uppercase))
+ golden = ''.join(('map_string_string {\n key: "%c"\n value: "dummy"\n}\n'
+ % (letter,) for letter in string.ascii_uppercase))
self.CompareToGoldenText(text_format.MessageToString(message), golden)
def testMapOrderSemantics(self):
@@ -602,9 +586,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
# The C++ implementation emits defaulted-value fields, while the Python
# implementation does not. Adjusting for this is awkward, but it is
# valuable to test against a common golden file.
- line_blacklist = (' key: 0\n',
- ' value: 0\n',
- ' key: false\n',
+ line_blacklist = (' key: 0\n', ' value: 0\n', ' key: false\n',
' value: false\n')
golden_lines = [line for line in golden_lines if line not in line_blacklist]
@@ -627,8 +609,7 @@ class Proto2Tests(TextFormatBase):
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
self.CompareToGoldenText(
- text_format.MessageToString(message),
- 'message_set {\n'
+ text_format.MessageToString(message), 'message_set {\n'
' [protobuf_unittest.TestMessageSetExtension1] {\n'
' i: 23\n'
' }\n'
@@ -654,16 +635,14 @@ class Proto2Tests(TextFormatBase):
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
text_format.PrintMessage(message, out, use_field_number=True)
- self.CompareToGoldenText(
- out.getvalue(),
- '1 {\n'
- ' 1545008 {\n'
- ' 15: 23\n'
- ' }\n'
- ' 1547769 {\n'
- ' 25: \"foo\"\n'
- ' }\n'
- '}\n')
+ self.CompareToGoldenText(out.getvalue(), '1 {\n'
+ ' 1545008 {\n'
+ ' 15: 23\n'
+ ' }\n'
+ ' 1547769 {\n'
+ ' 25: \"foo\"\n'
+ ' }\n'
+ '}\n')
out.close()
def testPrintMessageSetAsOneLine(self):
@@ -685,8 +664,7 @@ class Proto2Tests(TextFormatBase):
def testParseMessageSet(self):
message = unittest_pb2.TestAllTypes()
- text = ('repeated_uint64: 1\n'
- 'repeated_uint64: 2\n')
+ text = ('repeated_uint64: 1\n' 'repeated_uint64: 2\n')
text_format.Parse(text, message)
self.assertEqual(1, message.repeated_uint64[0])
self.assertEqual(2, message.repeated_uint64[1])
@@ -708,8 +686,7 @@ class Proto2Tests(TextFormatBase):
def testParseMessageByFieldNumber(self):
message = unittest_pb2.TestAllTypes()
- text = ('34: 1\n'
- 'repeated_uint64: 2\n')
+ text = ('34: 1\n' 'repeated_uint64: 2\n')
text_format.Parse(text, message, allow_field_number=True)
self.assertEqual(1, message.repeated_uint64[0])
self.assertEqual(2, message.repeated_uint64[1])
@@ -732,12 +709,9 @@ class Proto2Tests(TextFormatBase):
# Can't parse field number without set allow_field_number=True.
message = unittest_pb2.TestAllTypes()
text = '34:1\n'
- six.assertRaisesRegex(
- self,
- text_format.ParseError,
- (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
- r'"34".'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+ r'"34".'), text_format.Parse, text, message)
# Can't parse if field number is not found.
text = '1234:1\n'
@@ -746,7 +720,10 @@ class Proto2Tests(TextFormatBase):
text_format.ParseError,
(r'1:1 : Message type "\w+.TestAllTypes" has no field named '
r'"1234".'),
- text_format.Parse, text, message, allow_field_number=True)
+ text_format.Parse,
+ text,
+ message,
+ allow_field_number=True)
def testPrintAllExtensions(self):
message = unittest_pb2.TestAllExtensions()
@@ -824,7 +801,9 @@ class Proto2Tests(TextFormatBase):
six.assertRaisesRegex(self,
text_format.ParseError,
'Invalid field value: }',
- text_format.Parse, malformed, message,
+ text_format.Parse,
+ malformed,
+ message,
allow_unknown_extension=True)
message = unittest_mset_pb2.TestMessageSetContainer()
@@ -836,7 +815,9 @@ class Proto2Tests(TextFormatBase):
six.assertRaisesRegex(self,
text_format.ParseError,
'Invalid field value: "',
- text_format.Parse, malformed, message,
+ text_format.Parse,
+ malformed,
+ message,
allow_unknown_extension=True)
message = unittest_mset_pb2.TestMessageSetContainer()
@@ -848,7 +829,9 @@ class Proto2Tests(TextFormatBase):
six.assertRaisesRegex(self,
text_format.ParseError,
'Invalid field value: "',
- text_format.Parse, malformed, message,
+ text_format.Parse,
+ malformed,
+ message,
allow_unknown_extension=True)
message = unittest_mset_pb2.TestMessageSetContainer()
@@ -860,7 +843,9 @@ class Proto2Tests(TextFormatBase):
six.assertRaisesRegex(self,
text_format.ParseError,
'5:1 : Expected ">".',
- text_format.Parse, malformed, message,
+ text_format.Parse,
+ malformed,
+ message,
allow_unknown_extension=True)
# Don't allow unknown fields with allow_unknown_extension=True.
@@ -874,7 +859,9 @@ class Proto2Tests(TextFormatBase):
('2:3 : Message type '
'"proto2_wireformat_unittest.TestMessageSet" has no'
' field named "unknown_field".'),
- text_format.Parse, malformed, message,
+ text_format.Parse,
+ malformed,
+ message,
allow_unknown_extension=True)
# Parse known extension correcty.
@@ -896,67 +883,57 @@ class Proto2Tests(TextFormatBase):
def testParseBadExtension(self):
message = unittest_pb2.TestAllExtensions()
text = '[unknown_extension]: 8\n'
- six.assertRaisesRegex(self,
- text_format.ParseError,
- '1:2 : Extension "unknown_extension" not registered.',
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError,
+ '1:2 : Extension "unknown_extension" not registered.',
+ text_format.Parse, text, message)
message = unittest_pb2.TestAllTypes()
- six.assertRaisesRegex(self,
- text_format.ParseError,
- ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
- 'extensions.'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ '1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
+ 'extensions.'), text_format.Parse, text, message)
def testMergeDuplicateExtensionScalars(self):
message = unittest_pb2.TestAllExtensions()
text = ('[protobuf_unittest.optional_int32_extension]: 42 '
'[protobuf_unittest.optional_int32_extension]: 67')
text_format.Merge(text, message)
- self.assertEqual(
- 67,
- message.Extensions[unittest_pb2.optional_int32_extension])
+ self.assertEqual(67,
+ message.Extensions[unittest_pb2.optional_int32_extension])
def testParseDuplicateExtensionScalars(self):
message = unittest_pb2.TestAllExtensions()
text = ('[protobuf_unittest.optional_int32_extension]: 42 '
'[protobuf_unittest.optional_int32_extension]: 67')
- six.assertRaisesRegex(self,
- text_format.ParseError,
- ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
- 'should not have multiple '
- '"protobuf_unittest.optional_int32_extension" extensions.'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ '1:96 : Message type "protobuf_unittest.TestAllExtensions" '
+ 'should not have multiple '
+ '"protobuf_unittest.optional_int32_extension" extensions.'),
+ text_format.Parse, text, message)
def testParseDuplicateNestedMessageScalars(self):
message = unittest_pb2.TestAllTypes()
text = ('optional_nested_message { bb: 1 } '
'optional_nested_message { bb: 2 }')
- six.assertRaisesRegex(self,
- text_format.ParseError,
- ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
- 'should not have multiple "bb" fields.'),
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ '1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
+ 'should not have multiple "bb" fields.'), text_format.Parse, text,
+ message)
def testParseDuplicateScalars(self):
message = unittest_pb2.TestAllTypes()
- text = ('optional_int32: 42 '
- 'optional_int32: 67')
- six.assertRaisesRegex(self,
- text_format.ParseError,
- ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
- 'have multiple "optional_int32" fields.'),
- text_format.Parse, text, message)
+ text = ('optional_int32: 42 ' 'optional_int32: 67')
+ six.assertRaisesRegex(self, text_format.ParseError, (
+ '1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
+ 'have multiple "optional_int32" fields.'), text_format.Parse, text,
+ message)
def testParseGroupNotClosed(self):
message = unittest_pb2.TestAllTypes()
text = 'RepeatedGroup: <'
- six.assertRaisesRegex(self,
- text_format.ParseError, '1:16 : Expected ">".',
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected ">".',
+ text_format.Parse, text, message)
text = 'RepeatedGroup: {'
- six.assertRaisesRegex(self,
- text_format.ParseError, '1:16 : Expected "}".',
- text_format.Parse, text, message)
+ six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected "}".',
+ text_format.Parse, text, message)
def testParseEmptyGroup(self):
message = unittest_pb2.TestAllTypes()
@@ -1007,10 +984,197 @@ class Proto2Tests(TextFormatBase):
self.assertEqual(-2**34, message.map_int64_int64[-2**33])
self.assertEqual(456, message.map_uint32_uint32[123])
self.assertEqual(2**34, message.map_uint64_uint64[2**33])
- self.assertEqual("123", message.map_string_string["abc"])
+ self.assertEqual('123', message.map_string_string['abc'])
self.assertEqual(5, message.map_int32_foreign_message[111].c)
+class Proto3Tests(unittest.TestCase):
+
+ def testPrintMessageExpandAny(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message,
+ descriptor_pool=descriptor_pool.Default()),
+ 'any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string"\n'
+ ' }\n'
+ '}\n')
+
+ def testPrintMessageExpandAnyRepeated(self):
+ packed_message = unittest_pb2.OneString()
+ message = any_test_pb2.TestAny()
+ packed_message.data = 'string0'
+ message.repeated_any_value.add().Pack(packed_message)
+ packed_message.data = 'string1'
+ message.repeated_any_value.add().Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message,
+ descriptor_pool=descriptor_pool.Default()),
+ 'repeated_any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string0"\n'
+ ' }\n'
+ '}\n'
+ 'repeated_any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string1"\n'
+ ' }\n'
+ '}\n')
+
+ def testPrintMessageExpandAnyNoDescriptorPool(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message, descriptor_pool=None),
+ 'any_value {\n'
+ ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+ ' value: "\\n\\006string"\n'
+ '}\n')
+
+ def testPrintMessageExpandAnyDescriptorPoolMissingType(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ empty_pool = descriptor_pool.DescriptorPool()
+ self.assertEqual(
+ text_format.MessageToString(message, descriptor_pool=empty_pool),
+ 'any_value {\n'
+ ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+ ' value: "\\n\\006string"\n'
+ '}\n')
+
+ def testPrintMessageExpandAnyPointyBrackets(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message,
+ pointy_brackets=True,
+ descriptor_pool=descriptor_pool.Default()),
+ 'any_value <\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] <\n'
+ ' data: "string"\n'
+ ' >\n'
+ '>\n')
+
+ def testPrintMessageExpandAnyAsOneLine(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message,
+ as_one_line=True,
+ descriptor_pool=descriptor_pool.Default()),
+ 'any_value {'
+ ' [type.googleapis.com/protobuf_unittest.OneString]'
+ ' { data: "string" } '
+ '}')
+
+ def testPrintMessageExpandAnyAsOneLinePointyBrackets(self):
+ packed_message = unittest_pb2.OneString()
+ packed_message.data = 'string'
+ message = any_test_pb2.TestAny()
+ message.any_value.Pack(packed_message)
+ self.assertEqual(
+ text_format.MessageToString(message,
+ as_one_line=True,
+ pointy_brackets=True,
+ descriptor_pool=descriptor_pool.Default()),
+ 'any_value <'
+ ' [type.googleapis.com/protobuf_unittest.OneString]'
+ ' < data: "string" > '
+ '>')
+
+ def testMergeExpandedAny(self):
+ message = any_test_pb2.TestAny()
+ text = ('any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string"\n'
+ ' }\n'
+ '}\n')
+ text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+ packed_message = unittest_pb2.OneString()
+ message.any_value.Unpack(packed_message)
+ self.assertEqual('string', packed_message.data)
+
+ def testMergeExpandedAnyRepeated(self):
+ message = any_test_pb2.TestAny()
+ text = ('repeated_any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string0"\n'
+ ' }\n'
+ '}\n'
+ 'repeated_any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string1"\n'
+ ' }\n'
+ '}\n')
+ text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+ packed_message = unittest_pb2.OneString()
+ message.repeated_any_value[0].Unpack(packed_message)
+ self.assertEqual('string0', packed_message.data)
+ message.repeated_any_value[1].Unpack(packed_message)
+ self.assertEqual('string1', packed_message.data)
+
+ def testMergeExpandedAnyPointyBrackets(self):
+ message = any_test_pb2.TestAny()
+ text = ('any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] <\n'
+ ' data: "string"\n'
+ ' >\n'
+ '}\n')
+ text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+ packed_message = unittest_pb2.OneString()
+ message.any_value.Unpack(packed_message)
+ self.assertEqual('string', packed_message.data)
+
+ def testMergeExpandedAnyNoDescriptorPool(self):
+ message = any_test_pb2.TestAny()
+ text = ('any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string"\n'
+ ' }\n'
+ '}\n')
+ with self.assertRaises(text_format.ParseError) as e:
+ text_format.Merge(text, message, descriptor_pool=None)
+ self.assertEqual(str(e.exception),
+ 'Descriptor pool required to parse expanded Any field')
+
+ def testMergeExpandedAnyDescriptorPoolMissingType(self):
+ message = any_test_pb2.TestAny()
+ text = ('any_value {\n'
+ ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
+ ' data: "string"\n'
+ ' }\n'
+ '}\n')
+ with self.assertRaises(text_format.ParseError) as e:
+ empty_pool = descriptor_pool.DescriptorPool()
+ text_format.Merge(text, message, descriptor_pool=empty_pool)
+ self.assertEqual(
+ str(e.exception),
+ 'Type protobuf_unittest.OneString not found in descriptor pool')
+
+ def testMergeUnexpandedAny(self):
+ text = ('any_value {\n'
+ ' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+ ' value: "\\n\\006string"\n'
+ '}\n')
+ message = any_test_pb2.TestAny()
+ text_format.Merge(text, message)
+ packed_message = unittest_pb2.OneString()
+ message.any_value.Unpack(packed_message)
+ self.assertEqual('string', packed_message.data)
+
+
class TokenizerTest(unittest.TestCase):
def testSimpleTokenCases(self):
@@ -1021,79 +1185,55 @@ class TokenizerTest(unittest.TestCase):
'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f '
'false_bool: 0 true_BOOL:t \n true_bool1: 1 false_BOOL1:f ')
- tokenizer = text_format._Tokenizer(text.splitlines())
- methods = [(tokenizer.ConsumeIdentifier, 'identifier1'),
- ':',
+ tokenizer = text_format.Tokenizer(text.splitlines())
+ methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), ':',
(tokenizer.ConsumeString, 'string1'),
- (tokenizer.ConsumeIdentifier, 'identifier2'),
- ':',
- (tokenizer.ConsumeInt32, 123),
- (tokenizer.ConsumeIdentifier, 'identifier3'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'identifier2'), ':',
+ (tokenizer.ConsumeInteger, 123),
+ (tokenizer.ConsumeIdentifier, 'identifier3'), ':',
(tokenizer.ConsumeString, 'string'),
- (tokenizer.ConsumeIdentifier, 'identifiER_4'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'identifiER_4'), ':',
(tokenizer.ConsumeFloat, 1.1e+2),
- (tokenizer.ConsumeIdentifier, 'ID5'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'ID5'), ':',
(tokenizer.ConsumeFloat, -0.23),
- (tokenizer.ConsumeIdentifier, 'ID6'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'ID6'), ':',
(tokenizer.ConsumeString, 'aaaa\'bbbb'),
- (tokenizer.ConsumeIdentifier, 'ID7'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'ID7'), ':',
(tokenizer.ConsumeString, 'aa\"bb'),
- (tokenizer.ConsumeIdentifier, 'ID8'),
- ':',
- '{',
- (tokenizer.ConsumeIdentifier, 'A'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'ID8'), ':', '{',
+ (tokenizer.ConsumeIdentifier, 'A'), ':',
(tokenizer.ConsumeFloat, float('inf')),
- (tokenizer.ConsumeIdentifier, 'B'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'B'), ':',
(tokenizer.ConsumeFloat, -float('inf')),
- (tokenizer.ConsumeIdentifier, 'C'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'C'), ':',
(tokenizer.ConsumeBool, True),
- (tokenizer.ConsumeIdentifier, 'D'),
- ':',
- (tokenizer.ConsumeBool, False),
- '}',
- (tokenizer.ConsumeIdentifier, 'ID9'),
- ':',
- (tokenizer.ConsumeUint32, 22),
- (tokenizer.ConsumeIdentifier, 'ID10'),
- ':',
- (tokenizer.ConsumeInt64, -111111111111111111),
- (tokenizer.ConsumeIdentifier, 'ID11'),
- ':',
- (tokenizer.ConsumeInt32, -22),
- (tokenizer.ConsumeIdentifier, 'ID12'),
- ':',
- (tokenizer.ConsumeUint64, 2222222222222222222),
- (tokenizer.ConsumeIdentifier, 'ID13'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'D'), ':',
+ (tokenizer.ConsumeBool, False), '}',
+ (tokenizer.ConsumeIdentifier, 'ID9'), ':',
+ (tokenizer.ConsumeInteger, 22),
+ (tokenizer.ConsumeIdentifier, 'ID10'), ':',
+ (tokenizer.ConsumeInteger, -111111111111111111),
+ (tokenizer.ConsumeIdentifier, 'ID11'), ':',
+ (tokenizer.ConsumeInteger, -22),
+ (tokenizer.ConsumeIdentifier, 'ID12'), ':',
+ (tokenizer.ConsumeInteger, 2222222222222222222),
+ (tokenizer.ConsumeIdentifier, 'ID13'), ':',
(tokenizer.ConsumeFloat, 1.23456),
- (tokenizer.ConsumeIdentifier, 'ID14'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'ID14'), ':',
(tokenizer.ConsumeFloat, 1.2e+2),
- (tokenizer.ConsumeIdentifier, 'false_bool'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'false_bool'), ':',
(tokenizer.ConsumeBool, False),
- (tokenizer.ConsumeIdentifier, 'true_BOOL'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'true_BOOL'), ':',
(tokenizer.ConsumeBool, True),
- (tokenizer.ConsumeIdentifier, 'true_bool1'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'true_bool1'), ':',
(tokenizer.ConsumeBool, True),
- (tokenizer.ConsumeIdentifier, 'false_BOOL1'),
- ':',
+ (tokenizer.ConsumeIdentifier, 'false_BOOL1'), ':',
(tokenizer.ConsumeBool, False)]
i = 0
while not tokenizer.AtEnd():
m = methods[i]
- if type(m) == str:
+ if isinstance(m, str):
token = tokenizer.token
self.assertEqual(token, m)
tokenizer.NextToken()
@@ -1101,59 +1241,119 @@ class TokenizerTest(unittest.TestCase):
self.assertEqual(m[1], m[0]())
i += 1
- def testConsumeIntegers(self):
+ def testConsumeAbstractIntegers(self):
# This test only tests the failures in the integer parsing methods as well
# as the '0' special cases.
int64_max = (1 << 63) - 1
uint32_max = (1 << 32) - 1
text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
- tokenizer = text_format._Tokenizer(text.splitlines())
- self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
- self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64)
- self.assertEqual(-1, tokenizer.ConsumeInt32())
+ tokenizer = text_format.Tokenizer(text.splitlines())
+ self.assertEqual(-1, tokenizer.ConsumeInteger())
- self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
- self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32)
- self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64())
+ self.assertEqual(uint32_max + 1, tokenizer.ConsumeInteger())
- self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64)
- self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64())
+ self.assertEqual(int64_max + 1, tokenizer.ConsumeInteger())
+ self.assertTrue(tokenizer.AtEnd())
+
+ text = '-0 0'
+ tokenizer = text_format.Tokenizer(text.splitlines())
+ self.assertEqual(0, tokenizer.ConsumeInteger())
+ self.assertEqual(0, tokenizer.ConsumeInteger())
+ self.assertTrue(tokenizer.AtEnd())
+
+ def testConsumeIntegers(self):
+ # This test only tests the failures in the integer parsing methods as well
+ # as the '0' special cases.
+ int64_max = (1 << 63) - 1
+ uint32_max = (1 << 32) - 1
+ text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
+ tokenizer = text_format.Tokenizer(text.splitlines())
+ self.assertRaises(text_format.ParseError,
+ text_format._ConsumeUint32, tokenizer)
+ self.assertRaises(text_format.ParseError,
+ text_format._ConsumeUint64, tokenizer)
+ self.assertEqual(-1, text_format._ConsumeInt32(tokenizer))
+
+ self.assertRaises(text_format.ParseError,
+ text_format._ConsumeUint32, tokenizer)
+ self.assertRaises(text_format.ParseError,
+ text_format._ConsumeInt32, tokenizer)
+ self.assertEqual(uint32_max + 1, text_format._ConsumeInt64(tokenizer))
+
+ self.assertRaises(text_format.ParseError,
+ text_format._ConsumeInt64, tokenizer)
+ self.assertEqual(int64_max + 1, text_format._ConsumeUint64(tokenizer))
self.assertTrue(tokenizer.AtEnd())
text = '-0 -0 0 0'
- tokenizer = text_format._Tokenizer(text.splitlines())
- self.assertEqual(0, tokenizer.ConsumeUint32())
- self.assertEqual(0, tokenizer.ConsumeUint64())
- self.assertEqual(0, tokenizer.ConsumeUint32())
- self.assertEqual(0, tokenizer.ConsumeUint64())
+ tokenizer = text_format.Tokenizer(text.splitlines())
+ self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+ self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
+ self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+ self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
self.assertTrue(tokenizer.AtEnd())
def testConsumeByteString(self):
text = '"string1\''
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = 'string1"'
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\xt"'
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\"'
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\x"'
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
def testConsumeBool(self):
text = 'not-a-bool'
- tokenizer = text_format._Tokenizer(text.splitlines())
+ tokenizer = text_format.Tokenizer(text.splitlines())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
+ def testSkipComment(self):
+ tokenizer = text_format.Tokenizer('# some comment'.splitlines())
+ self.assertTrue(tokenizer.AtEnd())
+ self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+ def testConsumeComment(self):
+ tokenizer = text_format.Tokenizer('# some comment'.splitlines(),
+ skip_comments=False)
+ self.assertFalse(tokenizer.AtEnd())
+ self.assertEqual('# some comment', tokenizer.ConsumeComment())
+ self.assertTrue(tokenizer.AtEnd())
+
+ def testConsumeTwoComments(self):
+ text = '# some comment\n# another comment'
+ tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+ self.assertEqual('# some comment', tokenizer.ConsumeComment())
+ self.assertFalse(tokenizer.AtEnd())
+ self.assertEqual('# another comment', tokenizer.ConsumeComment())
+ self.assertTrue(tokenizer.AtEnd())
+
+ def testConsumeTrailingComment(self):
+ text = 'some_number: 4\n# some comment'
+ tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+ self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+ self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
+ self.assertEqual(tokenizer.token, ':')
+ tokenizer.NextToken()
+ self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+ self.assertEqual(4, tokenizer.ConsumeInteger())
+ self.assertFalse(tokenizer.AtEnd())
+
+ self.assertEqual('# some comment', tokenizer.ConsumeComment())
+ self.assertTrue(tokenizer.AtEnd())
+
if __name__ == '__main__':
unittest.main()
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index be6a9b63..bb6a1998 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -53,6 +53,7 @@ import re
import six
import sys
+from operator import methodcaller
from google.protobuf import descriptor
from google.protobuf import symbol_database
@@ -98,22 +99,8 @@ def MessageToJson(message, including_default_value_fields=False):
Returns:
A string containing the JSON formatted protocol buffer message.
"""
- js = _MessageToJsonObject(message, including_default_value_fields)
- return json.dumps(js, indent=2)
-
-
-def _MessageToJsonObject(message, including_default_value_fields):
- """Converts message to an object according to Proto3 JSON Specification."""
- message_descriptor = message.DESCRIPTOR
- full_name = message_descriptor.full_name
- if _IsWrapperMessage(message_descriptor):
- return _WrapperMessageToJsonObject(message)
- if full_name in _WKTJSONMETHODS:
- return _WKTJSONMETHODS[full_name][0](
- message, including_default_value_fields)
- js = {}
- return _RegularMessageToJsonObject(
- message, js, including_default_value_fields)
+ printer = _Printer(including_default_value_fields)
+ return printer.ToJsonString(message)
def _IsMapEntry(field):
@@ -122,179 +109,179 @@ def _IsMapEntry(field):
field.message_type.GetOptions().map_entry)
-def _RegularMessageToJsonObject(message, js, including_default_value_fields):
- """Converts normal message according to Proto3 JSON Specification."""
- fields = message.ListFields()
- include_default = including_default_value_fields
+class _Printer(object):
+ """JSON format printer for protocol message."""
- try:
- for field, value in fields:
- name = field.camelcase_name
- if _IsMapEntry(field):
- # Convert a map field.
- v_field = field.message_type.fields_by_name['value']
- js_map = {}
- for key in value:
- if isinstance(key, bool):
- if key:
- recorded_key = 'true'
- else:
- recorded_key = 'false'
- else:
- recorded_key = key
- js_map[recorded_key] = _FieldToJsonObject(
- v_field, value[key], including_default_value_fields)
- js[name] = js_map
- elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
- # Convert a repeated field.
- js[name] = [_FieldToJsonObject(field, k, include_default)
- for k in value]
- else:
- js[name] = _FieldToJsonObject(field, value, include_default)
-
- # Serialize default value if including_default_value_fields is True.
- if including_default_value_fields:
- message_descriptor = message.DESCRIPTOR
- for field in message_descriptor.fields:
- # Singular message fields and oneof fields will not be affected.
- if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
- field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
- field.containing_oneof):
- continue
- name = field.camelcase_name
- if name in js:
- # Skip the field which has been serailized already.
- continue
- if _IsMapEntry(field):
- js[name] = {}
- elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
- js[name] = []
- else:
- js[name] = _FieldToJsonObject(field, field.default_value)
+ def __init__(self,
+ including_default_value_fields=False):
+ self.including_default_value_fields = including_default_value_fields
- except ValueError as e:
- raise SerializeToJsonError(
- 'Failed to serialize {0} field: {1}.'.format(field.name, e))
+ def ToJsonString(self, message):
+ js = self._MessageToJsonObject(message)
+ return json.dumps(js, indent=2)
- return js
+ def _MessageToJsonObject(self, message):
+ """Converts message to an object according to Proto3 JSON Specification."""
+ message_descriptor = message.DESCRIPTOR
+ full_name = message_descriptor.full_name
+ if _IsWrapperMessage(message_descriptor):
+ return self._WrapperMessageToJsonObject(message)
+ if full_name in _WKTJSONMETHODS:
+ return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self)
+ js = {}
+ return self._RegularMessageToJsonObject(message, js)
+ def _RegularMessageToJsonObject(self, message, js):
+ """Converts normal message according to Proto3 JSON Specification."""
+ fields = message.ListFields()
-def _FieldToJsonObject(
- field, value, including_default_value_fields=False):
- """Converts field value according to Proto3 JSON Specification."""
- if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
- return _MessageToJsonObject(value, including_default_value_fields)
- elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
- enum_value = field.enum_type.values_by_number.get(value, None)
- if enum_value is not None:
- return enum_value.name
- else:
- raise SerializeToJsonError('Enum field contains an integer value '
- 'which can not mapped to an enum value.')
- elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
- if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
- # Use base64 Data encoding for bytes
- return base64.b64encode(value).decode('utf-8')
- else:
- return value
- elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
- return bool(value)
- elif field.cpp_type in _INT64_TYPES:
- return str(value)
- elif field.cpp_type in _FLOAT_TYPES:
- if math.isinf(value):
- if value < 0.0:
- return _NEG_INFINITY
- else:
- return _INFINITY
- if math.isnan(value):
- return _NAN
- return value
+ try:
+ for field, value in fields:
+ name = field.camelcase_name
+ if _IsMapEntry(field):
+ # Convert a map field.
+ v_field = field.message_type.fields_by_name['value']
+ js_map = {}
+ for key in value:
+ if isinstance(key, bool):
+ if key:
+ recorded_key = 'true'
+ else:
+ recorded_key = 'false'
+ else:
+ recorded_key = key
+ js_map[recorded_key] = self._FieldToJsonObject(
+ v_field, value[key])
+ js[name] = js_map
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ # Convert a repeated field.
+ js[name] = [self._FieldToJsonObject(field, k)
+ for k in value]
+ else:
+ js[name] = self._FieldToJsonObject(field, value)
+
+ # Serialize default value if including_default_value_fields is True.
+ if self.including_default_value_fields:
+ message_descriptor = message.DESCRIPTOR
+ for field in message_descriptor.fields:
+ # Singular message fields and oneof fields will not be affected.
+ if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
+ field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
+ field.containing_oneof):
+ continue
+ name = field.camelcase_name
+ if name in js:
+ # Skip the field which has been serailized already.
+ continue
+ if _IsMapEntry(field):
+ js[name] = {}
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ js[name] = []
+ else:
+ js[name] = self._FieldToJsonObject(field, field.default_value)
+ except ValueError as e:
+ raise SerializeToJsonError(
+ 'Failed to serialize {0} field: {1}.'.format(field.name, e))
-def _AnyMessageToJsonObject(message, including_default):
- """Converts Any message according to Proto3 JSON Specification."""
- if not message.ListFields():
- return {}
- # Must print @type first, use OrderedDict instead of {}
- js = OrderedDict()
- type_url = message.type_url
- js['@type'] = type_url
- sub_message = _CreateMessageFromTypeUrl(type_url)
- sub_message.ParseFromString(message.value)
- message_descriptor = sub_message.DESCRIPTOR
- full_name = message_descriptor.full_name
- if _IsWrapperMessage(message_descriptor):
- js['value'] = _WrapperMessageToJsonObject(sub_message)
return js
- if full_name in _WKTJSONMETHODS:
- js['value'] = _WKTJSONMETHODS[full_name][0](sub_message, including_default)
- return js
- return _RegularMessageToJsonObject(sub_message, js, including_default)
-
-
-def _CreateMessageFromTypeUrl(type_url):
- # TODO(jieluo): Should add a way that users can register the type resolver
- # instead of the default one.
- db = symbol_database.Default()
- type_name = type_url.split('/')[-1]
- try:
- message_descriptor = db.pool.FindMessageTypeByName(type_name)
- except KeyError:
- raise TypeError(
- 'Can not find message descriptor by type_url: {0}.'.format(type_url))
- message_class = db.GetPrototype(message_descriptor)
- return message_class()
-
-
-def _GenericMessageToJsonObject(message, unused_including_default):
- """Converts message by ToJsonString according to Proto3 JSON Specification."""
- # Duration, Timestamp and FieldMask have ToJsonString method to do the
- # convert. Users can also call the method directly.
- return message.ToJsonString()
-
-
-def _ValueMessageToJsonObject(message, unused_including_default=False):
- """Converts Value message according to Proto3 JSON Specification."""
- which = message.WhichOneof('kind')
- # If the Value message is not set treat as null_value when serialize
- # to JSON. The parse back result will be different from original message.
- if which is None or which == 'null_value':
- return None
- if which == 'list_value':
- return _ListValueMessageToJsonObject(message.list_value)
- if which == 'struct_value':
- value = message.struct_value
- else:
- value = getattr(message, which)
- oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
- return _FieldToJsonObject(oneof_descriptor, value)
+ def _FieldToJsonObject(self, field, value):
+ """Converts field value according to Proto3 JSON Specification."""
+ if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ return self._MessageToJsonObject(value)
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+ enum_value = field.enum_type.values_by_number.get(value, None)
+ if enum_value is not None:
+ return enum_value.name
+ else:
+ raise SerializeToJsonError('Enum field contains an integer value '
+ 'which can not mapped to an enum value.')
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+ if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+ # Use base64 Data encoding for bytes
+ return base64.b64encode(value).decode('utf-8')
+ else:
+ return value
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+ return bool(value)
+ elif field.cpp_type in _INT64_TYPES:
+ return str(value)
+ elif field.cpp_type in _FLOAT_TYPES:
+ if math.isinf(value):
+ if value < 0.0:
+ return _NEG_INFINITY
+ else:
+ return _INFINITY
+ if math.isnan(value):
+ return _NAN
+ return value
+
+ def _AnyMessageToJsonObject(self, message):
+ """Converts Any message according to Proto3 JSON Specification."""
+ if not message.ListFields():
+ return {}
+ # Must print @type first, use OrderedDict instead of {}
+ js = OrderedDict()
+ type_url = message.type_url
+ js['@type'] = type_url
+ sub_message = _CreateMessageFromTypeUrl(type_url)
+ sub_message.ParseFromString(message.value)
+ message_descriptor = sub_message.DESCRIPTOR
+ full_name = message_descriptor.full_name
+ if _IsWrapperMessage(message_descriptor):
+ js['value'] = self._WrapperMessageToJsonObject(sub_message)
+ return js
+ if full_name in _WKTJSONMETHODS:
+ js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0],
+ sub_message)(self)
+ return js
+ return self._RegularMessageToJsonObject(sub_message, js)
+
+ def _GenericMessageToJsonObject(self, message):
+ """Converts message according to Proto3 JSON Specification."""
+ # Duration, Timestamp and FieldMask have ToJsonString method to do the
+ # convert. Users can also call the method directly.
+ return message.ToJsonString()
+
+ def _ValueMessageToJsonObject(self, message):
+ """Converts Value message according to Proto3 JSON Specification."""
+ which = message.WhichOneof('kind')
+ # If the Value message is not set treat as null_value when serialize
+ # to JSON. The parse back result will be different from original message.
+ if which is None or which == 'null_value':
+ return None
+ if which == 'list_value':
+ return self._ListValueMessageToJsonObject(message.list_value)
+ if which == 'struct_value':
+ value = message.struct_value
+ else:
+ value = getattr(message, which)
+ oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
+ return self._FieldToJsonObject(oneof_descriptor, value)
-def _ListValueMessageToJsonObject(message, unused_including_default=False):
- """Converts ListValue message according to Proto3 JSON Specification."""
- return [_ValueMessageToJsonObject(value)
- for value in message.values]
+ def _ListValueMessageToJsonObject(self, message):
+ """Converts ListValue message according to Proto3 JSON Specification."""
+ return [self._ValueMessageToJsonObject(value)
+ for value in message.values]
+ def _StructMessageToJsonObject(self, message):
+ """Converts Struct message according to Proto3 JSON Specification."""
+ fields = message.fields
+ ret = {}
+ for key in fields:
+ ret[key] = self._ValueMessageToJsonObject(fields[key])
+ return ret
-def _StructMessageToJsonObject(message, unused_including_default=False):
- """Converts Struct message according to Proto3 JSON Specification."""
- fields = message.fields
- ret = {}
- for key in fields:
- ret[key] = _ValueMessageToJsonObject(fields[key])
- return ret
+ def _WrapperMessageToJsonObject(self, message):
+ return self._FieldToJsonObject(
+ message.DESCRIPTOR.fields_by_name['value'], message.value)
def _IsWrapperMessage(message_descriptor):
return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
-def _WrapperMessageToJsonObject(message):
- return _FieldToJsonObject(
- message.DESCRIPTOR.fields_by_name['value'], message.value)
-
-
def _DuplicateChecker(js):
result = {}
for name, value in js:
@@ -304,12 +291,27 @@ def _DuplicateChecker(js):
return result
-def Parse(text, message):
+def _CreateMessageFromTypeUrl(type_url):
+ # TODO(jieluo): Should add a way that users can register the type resolver
+ # instead of the default one.
+ db = symbol_database.Default()
+ type_name = type_url.split('/')[-1]
+ try:
+ message_descriptor = db.pool.FindMessageTypeByName(type_name)
+ except KeyError:
+ raise TypeError(
+ 'Can not find message descriptor by type_url: {0}.'.format(type_url))
+ message_class = db.GetPrototype(message_descriptor)
+ return message_class()
+
+
+def Parse(text, message, ignore_unknown_fields=False):
"""Parses a JSON representation of a protocol message into a message.
Args:
text: Message JSON representation.
message: A protocol beffer message to merge into.
+ ignore_unknown_fields: If True, do not raise errors for unknown fields.
Returns:
The same message passed as argument.
@@ -326,213 +328,217 @@ def Parse(text, message):
js = json.loads(text, object_pairs_hook=_DuplicateChecker)
except ValueError as e:
raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
- _ConvertMessage(js, message)
+ parser = _Parser(ignore_unknown_fields)
+ parser.ConvertMessage(js, message)
return message
-def _ConvertFieldValuePair(js, message):
- """Convert field value pairs into regular message.
+_INT_OR_FLOAT = six.integer_types + (float,)
- Args:
- js: A JSON object to convert the field value pairs.
- message: A regular protocol message to record the data.
- Raises:
- ParseError: In case of problems converting.
- """
- names = []
- message_descriptor = message.DESCRIPTOR
- for name in js:
- try:
- field = message_descriptor.fields_by_camelcase_name.get(name, None)
- if not field:
- raise ParseError(
- 'Message type "{0}" has no field named "{1}".'.format(
- message_descriptor.full_name, name))
- if name in names:
- raise ParseError(
- 'Message type "{0}" should not have multiple "{1}" fields.'.format(
- message.DESCRIPTOR.full_name, name))
- names.append(name)
- # Check no other oneof field is parsed.
- if field.containing_oneof is not None:
- oneof_name = field.containing_oneof.name
- if oneof_name in names:
- raise ParseError('Message type "{0}" should not have multiple "{1}" '
- 'oneof fields.'.format(
- message.DESCRIPTOR.full_name, oneof_name))
- names.append(oneof_name)
-
- value = js[name]
- if value is None:
- message.ClearField(field.name)
- continue
-
- # Parse field value.
- if _IsMapEntry(field):
- message.ClearField(field.name)
- _ConvertMapFieldValue(value, message, field)
- elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
- message.ClearField(field.name)
- if not isinstance(value, list):
- raise ParseError('repeated field {0} must be in [] which is '
- '{1}.'.format(name, value))
- if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
- # Repeated message field.
- for item in value:
- sub_message = getattr(message, field.name).add()
- # None is a null_value in Value.
- if (item is None and
- sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
- raise ParseError('null is not allowed to be used as an element'
- ' in a repeated field.')
- _ConvertMessage(item, sub_message)
- else:
- # Repeated scalar field.
- for item in value:
- if item is None:
- raise ParseError('null is not allowed to be used as an element'
- ' in a repeated field.')
- getattr(message, field.name).append(
- _ConvertScalarFieldValue(item, field))
- elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
- sub_message = getattr(message, field.name)
- _ConvertMessage(value, sub_message)
- else:
- setattr(message, field.name, _ConvertScalarFieldValue(value, field))
- except ParseError as e:
- if field and field.containing_oneof is None:
- raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
- else:
- raise ParseError(str(e))
- except ValueError as e:
- raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
- except TypeError as e:
- raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+class _Parser(object):
+ """JSON format parser for protocol message."""
+ def __init__(self,
+ ignore_unknown_fields):
+ self.ignore_unknown_fields = ignore_unknown_fields
-def _ConvertMessage(value, message):
- """Convert a JSON object into a message.
+ def ConvertMessage(self, value, message):
+ """Convert a JSON object into a message.
- Args:
- value: A JSON object.
- message: A WKT or regular protocol message to record the data.
+ Args:
+ value: A JSON object.
+ message: A WKT or regular protocol message to record the data.
- Raises:
- ParseError: In case of convert problems.
- """
- message_descriptor = message.DESCRIPTOR
- full_name = message_descriptor.full_name
- if _IsWrapperMessage(message_descriptor):
- _ConvertWrapperMessage(value, message)
- elif full_name in _WKTJSONMETHODS:
- _WKTJSONMETHODS[full_name][1](value, message)
- else:
- _ConvertFieldValuePair(value, message)
-
-
-def _ConvertAnyMessage(value, message):
- """Convert a JSON representation into Any message."""
- if isinstance(value, dict) and not value:
- return
- try:
- type_url = value['@type']
- except KeyError:
- raise ParseError('@type is missing when parsing any message.')
-
- sub_message = _CreateMessageFromTypeUrl(type_url)
- message_descriptor = sub_message.DESCRIPTOR
- full_name = message_descriptor.full_name
- if _IsWrapperMessage(message_descriptor):
- _ConvertWrapperMessage(value['value'], sub_message)
- elif full_name in _WKTJSONMETHODS:
- _WKTJSONMETHODS[full_name][1](value['value'], sub_message)
- else:
- del value['@type']
- _ConvertFieldValuePair(value, sub_message)
- # Sets Any message
- message.value = sub_message.SerializeToString()
- message.type_url = type_url
-
-
-def _ConvertGenericMessage(value, message):
- """Convert a JSON representation into message with FromJsonString."""
- # Durantion, Timestamp, FieldMask have FromJsonString method to do the
- # convert. Users can also call the method directly.
- message.FromJsonString(value)
+ Raises:
+ ParseError: In case of convert problems.
+ """
+ message_descriptor = message.DESCRIPTOR
+ full_name = message_descriptor.full_name
+ if _IsWrapperMessage(message_descriptor):
+ self._ConvertWrapperMessage(value, message)
+ elif full_name in _WKTJSONMETHODS:
+ methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
+ else:
+ self._ConvertFieldValuePair(value, message)
+
+ def _ConvertFieldValuePair(self, js, message):
+ """Convert field value pairs into regular message.
+
+ Args:
+ js: A JSON object to convert the field value pairs.
+ message: A regular protocol message to record the data.
+
+ Raises:
+ ParseError: In case of problems converting.
+ """
+ names = []
+ message_descriptor = message.DESCRIPTOR
+ for name in js:
+ try:
+ field = message_descriptor.fields_by_camelcase_name.get(name, None)
+ if not field:
+ if self.ignore_unknown_fields:
+ continue
+ raise ParseError(
+ 'Message type "{0}" has no field named "{1}".'.format(
+ message_descriptor.full_name, name))
+ if name in names:
+ raise ParseError('Message type "{0}" should not have multiple '
+ '"{1}" fields.'.format(
+ message.DESCRIPTOR.full_name, name))
+ names.append(name)
+ # Check no other oneof field is parsed.
+ if field.containing_oneof is not None:
+ oneof_name = field.containing_oneof.name
+ if oneof_name in names:
+ raise ParseError('Message type "{0}" should not have multiple '
+ '"{1}" oneof fields.'.format(
+ message.DESCRIPTOR.full_name, oneof_name))
+ names.append(oneof_name)
+
+ value = js[name]
+ if value is None:
+ message.ClearField(field.name)
+ continue
+ # Parse field value.
+ if _IsMapEntry(field):
+ message.ClearField(field.name)
+ self._ConvertMapFieldValue(value, message, field)
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ message.ClearField(field.name)
+ if not isinstance(value, list):
+ raise ParseError('repeated field {0} must be in [] which is '
+ '{1}.'.format(name, value))
+ if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ # Repeated message field.
+ for item in value:
+ sub_message = getattr(message, field.name).add()
+ # None is a null_value in Value.
+ if (item is None and
+ sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
+ raise ParseError('null is not allowed to be used as an element'
+ ' in a repeated field.')
+ self.ConvertMessage(item, sub_message)
+ else:
+ # Repeated scalar field.
+ for item in value:
+ if item is None:
+ raise ParseError('null is not allowed to be used as an element'
+ ' in a repeated field.')
+ getattr(message, field.name).append(
+ _ConvertScalarFieldValue(item, field))
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ sub_message = getattr(message, field.name)
+ self.ConvertMessage(value, sub_message)
+ else:
+ setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+ except ParseError as e:
+ if field and field.containing_oneof is None:
+ raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+ else:
+ raise ParseError(str(e))
+ except ValueError as e:
+ raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+ except TypeError as e:
+ raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+
+ def _ConvertAnyMessage(self, value, message):
+ """Convert a JSON representation into Any message."""
+ if isinstance(value, dict) and not value:
+ return
+ try:
+ type_url = value['@type']
+ except KeyError:
+ raise ParseError('@type is missing when parsing any message.')
+
+ sub_message = _CreateMessageFromTypeUrl(type_url)
+ message_descriptor = sub_message.DESCRIPTOR
+ full_name = message_descriptor.full_name
+ if _IsWrapperMessage(message_descriptor):
+ self._ConvertWrapperMessage(value['value'], sub_message)
+ elif full_name in _WKTJSONMETHODS:
+ methodcaller(
+ _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self)
+ else:
+ del value['@type']
+ self._ConvertFieldValuePair(value, sub_message)
+ # Sets Any message
+ message.value = sub_message.SerializeToString()
+ message.type_url = type_url
+
+ def _ConvertGenericMessage(self, value, message):
+ """Convert a JSON representation into message with FromJsonString."""
+ # Durantion, Timestamp, FieldMask have FromJsonString method to do the
+ # convert. Users can also call the method directly.
+ message.FromJsonString(value)
+
+ def _ConvertValueMessage(self, value, message):
+ """Convert a JSON representation into Value message."""
+ if isinstance(value, dict):
+ self._ConvertStructMessage(value, message.struct_value)
+ elif isinstance(value, list):
+ self. _ConvertListValueMessage(value, message.list_value)
+ elif value is None:
+ message.null_value = 0
+ elif isinstance(value, bool):
+ message.bool_value = value
+ elif isinstance(value, six.string_types):
+ message.string_value = value
+ elif isinstance(value, _INT_OR_FLOAT):
+ message.number_value = value
+ else:
+ raise ParseError('Unexpected type for Value message.')
-_INT_OR_FLOAT = six.integer_types + (float,)
+ def _ConvertListValueMessage(self, value, message):
+ """Convert a JSON representation into ListValue message."""
+ if not isinstance(value, list):
+ raise ParseError(
+ 'ListValue must be in [] which is {0}.'.format(value))
+ message.ClearField('values')
+ for item in value:
+ self._ConvertValueMessage(item, message.values.add())
+
+ def _ConvertStructMessage(self, value, message):
+ """Convert a JSON representation into Struct message."""
+ if not isinstance(value, dict):
+ raise ParseError(
+ 'Struct must be in a dict which is {0}.'.format(value))
+ for key in value:
+ self._ConvertValueMessage(value[key], message.fields[key])
+ return
+ def _ConvertWrapperMessage(self, value, message):
+ """Convert a JSON representation into Wrapper message."""
+ field = message.DESCRIPTOR.fields_by_name['value']
+ setattr(message, 'value', _ConvertScalarFieldValue(value, field))
-def _ConvertValueMessage(value, message):
- """Convert a JSON representation into Value message."""
- if isinstance(value, dict):
- _ConvertStructMessage(value, message.struct_value)
- elif isinstance(value, list):
- _ConvertListValueMessage(value, message.list_value)
- elif value is None:
- message.null_value = 0
- elif isinstance(value, bool):
- message.bool_value = value
- elif isinstance(value, six.string_types):
- message.string_value = value
- elif isinstance(value, _INT_OR_FLOAT):
- message.number_value = value
- else:
- raise ParseError('Unexpected type for Value message.')
-
-
-def _ConvertListValueMessage(value, message):
- """Convert a JSON representation into ListValue message."""
- if not isinstance(value, list):
- raise ParseError(
- 'ListValue must be in [] which is {0}.'.format(value))
- message.ClearField('values')
- for item in value:
- _ConvertValueMessage(item, message.values.add())
-
-
-def _ConvertStructMessage(value, message):
- """Convert a JSON representation into Struct message."""
- if not isinstance(value, dict):
- raise ParseError(
- 'Struct must be in a dict which is {0}.'.format(value))
- for key in value:
- _ConvertValueMessage(value[key], message.fields[key])
- return
-
-
-def _ConvertWrapperMessage(value, message):
- """Convert a JSON representation into Wrapper message."""
- field = message.DESCRIPTOR.fields_by_name['value']
- setattr(message, 'value', _ConvertScalarFieldValue(value, field))
-
-
-def _ConvertMapFieldValue(value, message, field):
- """Convert map field value for a message map field.
+ def _ConvertMapFieldValue(self, value, message, field):
+ """Convert map field value for a message map field.
- Args:
- value: A JSON object to convert the map field value.
- message: A protocol message to record the converted data.
- field: The descriptor of the map field to be converted.
+ Args:
+ value: A JSON object to convert the map field value.
+ message: A protocol message to record the converted data.
+ field: The descriptor of the map field to be converted.
- Raises:
- ParseError: In case of convert problems.
- """
- if not isinstance(value, dict):
- raise ParseError(
- 'Map field {0} must be in a dict which is {1}.'.format(
- field.name, value))
- key_field = field.message_type.fields_by_name['key']
- value_field = field.message_type.fields_by_name['value']
- for key in value:
- key_value = _ConvertScalarFieldValue(key, key_field, True)
- if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
- _ConvertMessage(value[key], getattr(message, field.name)[key_value])
- else:
- getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
- value[key], value_field)
+ Raises:
+ ParseError: In case of convert problems.
+ """
+ if not isinstance(value, dict):
+ raise ParseError(
+ 'Map field {0} must be in a dict which is {1}.'.format(
+ field.name, value))
+ key_field = field.message_type.fields_by_name['key']
+ value_field = field.message_type.fields_by_name['value']
+ for key in value:
+ key_value = _ConvertScalarFieldValue(key, key_field, True)
+ if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ self.ConvertMessage(value[key], getattr(
+ message, field.name)[key_value])
+ else:
+ getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+ value[key], value_field)
def _ConvertScalarFieldValue(value, field, require_str=False):
@@ -641,18 +647,18 @@ def _ConvertBool(value, require_str):
return value
_WKTJSONMETHODS = {
- 'google.protobuf.Any': [_AnyMessageToJsonObject,
- _ConvertAnyMessage],
- 'google.protobuf.Duration': [_GenericMessageToJsonObject,
- _ConvertGenericMessage],
- 'google.protobuf.FieldMask': [_GenericMessageToJsonObject,
- _ConvertGenericMessage],
- 'google.protobuf.ListValue': [_ListValueMessageToJsonObject,
- _ConvertListValueMessage],
- 'google.protobuf.Struct': [_StructMessageToJsonObject,
- _ConvertStructMessage],
- 'google.protobuf.Timestamp': [_GenericMessageToJsonObject,
- _ConvertGenericMessage],
- 'google.protobuf.Value': [_ValueMessageToJsonObject,
- _ConvertValueMessage]
+ 'google.protobuf.Any': ['_AnyMessageToJsonObject',
+ '_ConvertAnyMessage'],
+ 'google.protobuf.Duration': ['_GenericMessageToJsonObject',
+ '_ConvertGenericMessage'],
+ 'google.protobuf.FieldMask': ['_GenericMessageToJsonObject',
+ '_ConvertGenericMessage'],
+ 'google.protobuf.ListValue': ['_ListValueMessageToJsonObject',
+ '_ConvertListValueMessage'],
+ 'google.protobuf.Struct': ['_StructMessageToJsonObject',
+ '_ConvertStructMessage'],
+ 'google.protobuf.Timestamp': ['_GenericMessageToJsonObject',
+ '_ConvertGenericMessage'],
+ 'google.protobuf.Value': ['_ValueMessageToJsonObject',
+ '_ConvertValueMessage']
}
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 23557538..e6ef5ef5 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -172,12 +172,16 @@ template<>
const FileDescriptor* GetFileDescriptor(const OneofDescriptor* descriptor) {
return descriptor->containing_type()->file();
}
+template<>
+const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) {
+ return descriptor->service()->file();
+}
// Converts options into a Python protobuf, and cache the result.
//
// This is a bit tricky because options can contain extension fields defined in
// the same proto file. In this case the options parsed from the serialized_pb
-// have unkown fields, and we need to parse them again.
+// have unknown fields, and we need to parse them again.
//
// Always returns a new reference.
template<class DescriptorClass>
@@ -204,11 +208,12 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
cdescriptor_pool::GetMessageClass(pool, message_type));
if (message_class == NULL) {
// The Options message was not found in the current DescriptorPool.
- // In this case, there cannot be extensions to these options, and we can
- // try to use the basic pool instead.
+ // This means that the pool cannot contain any extensions to the Options
+ // message either, so falling back to the basic pool we can only increase
+ // the chances of successfully parsing the options.
PyErr_Clear();
- message_class = cdescriptor_pool::GetMessageClass(
- GetDefaultDescriptorPool(), message_type);
+ pool = GetDefaultDescriptorPool();
+ message_class = cdescriptor_pool::GetMessageClass(pool, message_type);
}
if (message_class == NULL) {
PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
@@ -248,7 +253,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
// Cache the result.
Py_INCREF(value.get());
- (*pool->descriptor_options)[descriptor] = value.get();
+ (*descriptor_options)[descriptor] = value.get();
return value.release();
}
@@ -1091,7 +1096,7 @@ PyTypeObject PyEnumDescriptor_Type = {
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
- enum_descriptor::Methods, // tp_getset
+ enum_descriptor::Methods, // tp_methods
0, // tp_members
enum_descriptor::Getters, // tp_getset
&descriptor::PyBaseDescriptor_Type, // tp_base
@@ -1275,6 +1280,10 @@ static PyObject* GetExtensionsByName(PyFileDescriptor* self, void *closure) {
return NewFileExtensionsByName(_GetDescriptor(self));
}
+static PyObject* GetServicesByName(PyFileDescriptor* self, void *closure) {
+ return NewFileServicesByName(_GetDescriptor(self));
+}
+
static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) {
return NewFileDependencies(_GetDescriptor(self));
}
@@ -1324,6 +1333,7 @@ static PyGetSetDef Getters[] = {
{ "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"},
{ "extensions_by_name", (getter)GetExtensionsByName, NULL,
"Extensions by name"},
+ { "services_by_name", (getter)GetServicesByName, NULL, "Services by name"},
{ "dependencies", (getter)GetDependencies, NULL, "Dependencies"},
{ "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"},
@@ -1452,16 +1462,45 @@ static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
}
}
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+ const OneofOptions& options(_GetDescriptor(self)->options());
+ if (&options != &OneofOptions::default_instance()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+ void *closure) {
+ return CheckCalledFromGeneratedFile("_options");
+}
+
static PyGetSetDef Getters[] = {
{ "name", (getter)GetName, NULL, "Name"},
{ "full_name", (getter)GetFullName, NULL, "Full name"},
{ "index", (getter)GetIndex, NULL, "Index"},
{ "containing_type", (getter)GetContainingType, NULL, "Containing type"},
+ { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+ { "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "fields", (getter)GetFields, NULL, "Fields"},
{NULL}
};
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
+ {NULL}
+};
+
} // namespace oneof_descriptor
PyTypeObject PyOneofDescriptor_Type = {
@@ -1492,7 +1531,7 @@ PyTypeObject PyOneofDescriptor_Type = {
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
- 0, // tp_methods
+ oneof_descriptor::Methods, // tp_methods
0, // tp_members
oneof_descriptor::Getters, // tp_getset
&descriptor::PyBaseDescriptor_Type, // tp_base
@@ -1504,6 +1543,222 @@ PyObject* PyOneofDescriptor_FromDescriptor(
&PyOneofDescriptor_Type, oneof_descriptor, NULL);
}
+namespace service_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const ServiceDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const ServiceDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetMethods(PyBaseDescriptor* self, void *closure) {
+ return NewServiceMethodsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetMethodsByName(PyBaseDescriptor* self, void *closure) {
+ return NewServiceMethodsByName(_GetDescriptor(self));
+}
+
+static PyObject* FindMethodByName(PyBaseDescriptor *self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const MethodDescriptor* method_descriptor =
+ _GetDescriptor(self)->FindMethodByName(string(name, name_size));
+ if (method_descriptor == NULL) {
+ PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
+ return NULL;
+ }
+
+ return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+ return CopyToPythonProto<ServiceDescriptorProto>(_GetDescriptor(self),
+ target);
+}
+
+static PyGetSetDef Getters[] = {
+ { "name", (getter)GetName, NULL, "Name", NULL},
+ { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
+ { "index", (getter)GetIndex, NULL, "Index", NULL},
+
+ { "methods", (getter)GetMethods, NULL, "Methods", NULL},
+ { "methods_by_name", (getter)GetMethodsByName, NULL, "Methods by name", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
+ { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+ { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O },
+ {NULL}
+};
+
+} // namespace service_descriptor
+
+PyTypeObject PyServiceDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ FULL_MODULE_NAME ".ServiceDescriptor", // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "A Service Descriptor", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ service_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ service_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyServiceDescriptor_FromDescriptor(
+ const ServiceDescriptor* service_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyServiceDescriptor_Type, service_descriptor, NULL);
+}
+
+namespace method_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const MethodDescriptor* _GetDescriptor(
+ PyBaseDescriptor *self) {
+ return reinterpret_cast<const MethodDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+ return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetContainingService(PyBaseDescriptor *self, void *closure) {
+ const ServiceDescriptor* containing_service =
+ _GetDescriptor(self)->service();
+ return PyServiceDescriptor_FromDescriptor(containing_service);
+}
+
+static PyObject* GetInputType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* input_type = _GetDescriptor(self)->input_type();
+ return PyMessageDescriptor_FromDescriptor(input_type);
+}
+
+static PyObject* GetOutputType(PyBaseDescriptor *self, void *closure) {
+ const Descriptor* output_type = _GetDescriptor(self)->output_type();
+ return PyMessageDescriptor_FromDescriptor(output_type);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+ return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+ return CopyToPythonProto<MethodDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+ { "name", (getter)GetName, NULL, "Name", NULL},
+ { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
+ { "index", (getter)GetIndex, NULL, "Index", NULL},
+ { "containing_service", (getter)GetContainingService, NULL,
+ "Containing service", NULL},
+ { "input_type", (getter)GetInputType, NULL, "Input type", NULL},
+ { "output_type", (getter)GetOutputType, NULL, "Output type", NULL},
+ {NULL}
+};
+
+static PyMethodDef Methods[] = {
+ { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+ { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+ {NULL}
+};
+
+} // namespace method_descriptor
+
+PyTypeObject PyMethodDescriptor_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ FULL_MODULE_NAME ".MethodDescriptor", // tp_name
+ sizeof(PyBaseDescriptor), // tp_basicsize
+ 0, // tp_itemsize
+ 0, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ 0, // tp_repr
+ 0, // tp_as_number
+ 0, // tp_as_sequence
+ 0, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0, // tp_str
+ 0, // tp_getattro
+ 0, // tp_setattro
+ 0, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "A Method Descriptor", // tp_doc
+ 0, // tp_traverse
+ 0, // tp_clear
+ 0, // tp_richcompare
+ 0, // tp_weaklistoffset
+ 0, // tp_iter
+ 0, // tp_iternext
+ method_descriptor::Methods, // tp_methods
+ 0, // tp_members
+ method_descriptor::Getters, // tp_getset
+ &descriptor::PyBaseDescriptor_Type, // tp_base
+};
+
+PyObject* PyMethodDescriptor_FromDescriptor(
+ const MethodDescriptor* method_descriptor) {
+ return descriptor::NewInternedDescriptor(
+ &PyMethodDescriptor_Type, method_descriptor, NULL);
+}
+
// Add a enum values to a type dictionary.
static bool AddEnumValues(PyTypeObject *type,
const EnumDescriptor* enum_descriptor) {
@@ -1573,6 +1828,12 @@ bool InitDescriptor() {
if (PyType_Ready(&PyOneofDescriptor_Type) < 0)
return false;
+ if (PyType_Ready(&PyServiceDescriptor_Type) < 0)
+ return false;
+
+ if (PyType_Ready(&PyMethodDescriptor_Type) < 0)
+ return false;
+
if (!InitDescriptorMappingTypes())
return false;
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index eb99df18..1ae0e672 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -47,6 +47,8 @@ extern PyTypeObject PyEnumDescriptor_Type;
extern PyTypeObject PyEnumValueDescriptor_Type;
extern PyTypeObject PyFileDescriptor_Type;
extern PyTypeObject PyOneofDescriptor_Type;
+extern PyTypeObject PyServiceDescriptor_Type;
+extern PyTypeObject PyMethodDescriptor_Type;
// Wraps a Descriptor in a Python object.
// The C++ pointer is usually borrowed from the global DescriptorPool.
@@ -60,6 +62,10 @@ PyObject* PyEnumValueDescriptor_FromDescriptor(
PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor);
PyObject* PyFileDescriptor_FromDescriptor(
const FileDescriptor* file_descriptor);
+PyObject* PyServiceDescriptor_FromDescriptor(
+ const ServiceDescriptor* descriptor);
+PyObject* PyMethodDescriptor_FromDescriptor(
+ const MethodDescriptor* descriptor);
// Alternate constructor of PyFileDescriptor, used when we already have a
// serialized FileDescriptorProto that can be cached.
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index e505d812..d0aae9c9 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -608,6 +608,24 @@ static PyObject* GetItem(PyContainer* self, Py_ssize_t index) {
return _NewObj_ByIndex(self, index);
}
+static PyObject *
+SeqSubscript(PyContainer* self, PyObject* item) {
+ if (PyIndex_Check(item)) {
+ Py_ssize_t index;
+ index = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ return GetItem(self, index);
+ }
+ // Materialize the list and delegate the operation to it.
+ ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs(
+ reinterpret_cast<PyObject*>(&PyList_Type), self, NULL));
+ if (list == NULL) {
+ return NULL;
+ }
+ return Py_TYPE(list.get())->tp_as_mapping->mp_subscript(list.get(), item);
+}
+
// Returns the position of the item in the sequence, of -1 if not found.
// This function never fails.
int Find(PyContainer* self, PyObject* item) {
@@ -703,14 +721,20 @@ static PyMethodDef SeqMethods[] = {
};
static PySequenceMethods SeqSequenceMethods = {
- (lenfunc)Length, // sq_length
- 0, // sq_concat
- 0, // sq_repeat
- (ssizeargfunc)GetItem, // sq_item
- 0, // sq_slice
- 0, // sq_ass_item
- 0, // sq_ass_slice
- (objobjproc)SeqContains, // sq_contains
+ (lenfunc)Length, // sq_length
+ 0, // sq_concat
+ 0, // sq_repeat
+ (ssizeargfunc)GetItem, // sq_item
+ 0, // sq_slice
+ 0, // sq_ass_item
+ 0, // sq_ass_slice
+ (objobjproc)SeqContains, // sq_contains
+};
+
+static PyMappingMethods SeqMappingMethods = {
+ (lenfunc)Length, // mp_length
+ (binaryfunc)SeqSubscript, // mp_subscript
+ 0, // mp_ass_subscript
};
PyTypeObject DescriptorSequence_Type = {
@@ -726,7 +750,7 @@ PyTypeObject DescriptorSequence_Type = {
(reprfunc)ContainerRepr, // tp_repr
0, // tp_as_number
&SeqSequenceMethods, // tp_as_sequence
- 0, // tp_as_mapping
+ &SeqMappingMethods, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
@@ -1407,6 +1431,68 @@ PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) {
} // namespace oneof_descriptor
+namespace service_descriptor {
+
+typedef const ServiceDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+ return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace methods {
+
+typedef const MethodDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->method_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindMethodByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->method(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyMethodDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "ServiceMethods",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace methods
+
+PyObject* NewServiceMethodsSeq(ParentDescriptor descriptor) {
+ return descriptor::NewSequence(&methods::ContainerDef, descriptor);
+}
+
+PyObject* NewServiceMethodsByName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByName(&methods::ContainerDef, descriptor);
+}
+
+} // namespace service_descriptor
+
namespace file_descriptor {
typedef const FileDescriptor* ParentDescriptor;
@@ -1459,7 +1545,7 @@ static DescriptorContainerDef ContainerDef = {
} // namespace messages
-PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) {
+PyObject* NewFileMessageTypesByName(ParentDescriptor descriptor) {
return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
}
@@ -1507,7 +1593,7 @@ static DescriptorContainerDef ContainerDef = {
} // namespace enums
-PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) {
+PyObject* NewFileEnumTypesByName(ParentDescriptor descriptor) {
return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
}
@@ -1555,10 +1641,58 @@ static DescriptorContainerDef ContainerDef = {
} // namespace extensions
-PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) {
+PyObject* NewFileExtensionsByName(ParentDescriptor descriptor) {
return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
}
+namespace services {
+
+typedef const ServiceDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+ return GetDescriptor(self)->service_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+ return GetDescriptor(self)->FindServiceByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+ return GetDescriptor(self)->service(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+ return PyServiceDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+ return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+ return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+ "FileServices",
+ (CountMethod)Count,
+ (GetByIndexMethod)GetByIndex,
+ (GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
+ (GetByNumberMethod)NULL,
+ (NewObjectFromItemMethod)NewObjectFromItem,
+ (GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
+ (GetItemNumberMethod)NULL,
+ (GetItemIndexMethod)GetItemIndex,
+};
+
+} // namespace services
+
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor) {
+ return descriptor::NewMappingByName(&services::ContainerDef, descriptor);
+}
+
namespace dependencies {
typedef const FileDescriptor* ItemDescriptor;
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index ce40747d..83de07b6 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -43,6 +43,7 @@ class Descriptor;
class FileDescriptor;
class EnumDescriptor;
class OneofDescriptor;
+class ServiceDescriptor;
namespace python {
@@ -89,10 +90,17 @@ PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor);
PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor);
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor);
+
PyObject* NewFileDependencies(const FileDescriptor* descriptor);
PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor);
} // namespace file_descriptor
+namespace service_descriptor {
+PyObject* NewServiceMethodsSeq(const ServiceDescriptor* descriptor);
+PyObject* NewServiceMethodsByName(const ServiceDescriptor* descriptor);
+} // namespace service_descriptor
+
} // namespace python
} // namespace protobuf
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index 1faff96b..cfd98690 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -305,6 +305,40 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
}
+PyObject* FindServiceByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const ServiceDescriptor* service_descriptor =
+ self->pool->FindServiceByName(string(name, name_size));
+ if (service_descriptor == NULL) {
+ PyErr_Format(PyExc_KeyError, "Couldn't find service %.200s", name);
+ return NULL;
+ }
+
+ return PyServiceDescriptor_FromDescriptor(service_descriptor);
+}
+
+PyObject* FindMethodByName(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const MethodDescriptor* method_descriptor =
+ self->pool->FindMethodByName(string(name, name_size));
+ if (method_descriptor == NULL) {
+ PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
+ return NULL;
+ }
+
+ return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
Py_ssize_t name_size;
char* name;
@@ -491,6 +525,10 @@ static PyMethodDef Methods[] = {
"Searches for enum type descriptor by full name." },
{ "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
"Searches for oneof descriptor by full name." },
+ { "FindServiceByName", (PyCFunction)FindServiceByName, METH_O,
+ "Searches for service descriptor by full name." },
+ { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O,
+ "Searches for method descriptor by full name." },
{ "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
"Gets the FileDescriptor containing the specified symbol." },
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index e022406d..90438df1 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -39,7 +39,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/map_field.h>
#include <google/protobuf/map.h>
#include <google/protobuf/message.h>
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 83c151ff..a9261f20 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -1593,23 +1593,20 @@ struct ReleaseChild : public ChildVisitor {
parent_(parent) {}
int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
- return repeated_composite_container::Release(
- reinterpret_cast<RepeatedCompositeContainer*>(container));
+ return repeated_composite_container::Release(container);
}
int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
- return repeated_scalar_container::Release(
- reinterpret_cast<RepeatedScalarContainer*>(container));
+ return repeated_scalar_container::Release(container);
}
int VisitMapContainer(MapContainer* container) {
- return reinterpret_cast<MapContainer*>(container)->Release();
+ return container->Release();
}
int VisitCMessage(CMessage* cmessage,
const FieldDescriptor* field_descriptor) {
- return ReleaseSubMessage(parent_, field_descriptor,
- reinterpret_cast<CMessage*>(cmessage));
+ return ReleaseSubMessage(parent_, field_descriptor, cmessage);
}
CMessage* parent_;
@@ -1903,7 +1900,7 @@ static bool allow_oversize_protos = false;
// Provide a method in the module to set allow_oversize_protos to a boolean
// value. This method returns the newly value of allow_oversize_protos.
-static PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
if (!arg || !PyBool_Check(arg)) {
PyErr_SetString(PyExc_TypeError,
"Argument to SetAllowOversizeProtos must be boolean");
@@ -3044,6 +3041,10 @@ bool InitProto2MessageModule(PyObject *m) {
&PyFileDescriptor_Type));
PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast<PyObject*>(
&PyOneofDescriptor_Type));
+ PyModule_AddObject(m, "ServiceDescriptor", reinterpret_cast<PyObject*>(
+ &PyServiceDescriptor_Type));
+ PyModule_AddObject(m, "MethodDescriptor", reinterpret_cast<PyObject*>(
+ &PyMethodDescriptor_Type));
PyObject* enum_type_wrapper = PyImport_ImportModule(
"google.protobuf.internal.enum_type_wrapper");
@@ -3081,53 +3082,4 @@ bool InitProto2MessageModule(PyObject *m) {
} // namespace python
} // namespace protobuf
-static PyMethodDef ModuleMethods[] = {
- {"SetAllowOversizeProtos",
- (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
- METH_O, "Enable/disable oversize proto parsing."},
- { NULL, NULL}
-};
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef _module = {
- PyModuleDef_HEAD_INIT,
- "_message",
- google::protobuf::python::module_docstring,
- -1,
- ModuleMethods, /* m_methods */
- NULL,
- NULL,
- NULL,
- NULL
-};
-#define INITFUNC PyInit__message
-#define INITFUNC_ERRORVAL NULL
-#else // Python 2
-#define INITFUNC init_message
-#define INITFUNC_ERRORVAL
-#endif
-
-extern "C" {
- PyMODINIT_FUNC INITFUNC(void) {
- PyObject* m;
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&_module);
-#else
- m = Py_InitModule3("_message", ModuleMethods,
- google::protobuf::python::module_docstring);
-#endif
- if (m == NULL) {
- return INITFUNC_ERRORVAL;
- }
-
- if (!google::protobuf::python::InitProto2MessageModule(m)) {
- Py_DECREF(m);
- return INITFUNC_ERRORVAL;
- }
-
-#if PY_MAJOR_VERSION >= 3
- return m;
-#endif
- }
-}
} // namespace google
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 3a4bec81..8b399e05 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -54,7 +54,7 @@ class MessageFactory;
#ifdef _SHARED_PTR_H
using std::shared_ptr;
-using ::std::string;
+using std::string;
#else
using internal::shared_ptr;
#endif
@@ -269,6 +269,8 @@ int AssureWritable(CMessage* self);
// even in the case of extensions.
PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
+
} // namespace cmessage
@@ -354,6 +356,8 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
extern PyObject* PickleError_class;
+bool InitProto2MessageModule(PyObject *m);
+
} // namespace python
} // namespace protobuf
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
new file mode 100644
index 00000000..d90d9de3
--- /dev/null
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -0,0 +1,88 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/pyext/message.h>
+
+static const char module_docstring[] =
+"python-proto2 is a module that can be used to enhance proto2 Python API\n"
+"performance.\n"
+"\n"
+"It provides access to the protocol buffers C++ reflection API that\n"
+"implements the basic protocol buffer functions.";
+
+static PyMethodDef ModuleMethods[] = {
+ {"SetAllowOversizeProtos",
+ (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
+ METH_O, "Enable/disable oversize proto parsing."},
+ { NULL, NULL}
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef _module = {
+ PyModuleDef_HEAD_INIT,
+ "_message",
+ module_docstring,
+ -1,
+ ModuleMethods, /* m_methods */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#define INITFUNC PyInit__message
+#define INITFUNC_ERRORVAL NULL
+#else // Python 2
+#define INITFUNC init_message
+#define INITFUNC_ERRORVAL
+#endif
+
+extern "C" {
+ PyMODINIT_FUNC INITFUNC(void) {
+ PyObject* m;
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&_module);
+#else
+ m = Py_InitModule3("_message", ModuleMethods,
+ module_docstring);
+#endif
+ if (m == NULL) {
+ return INITFUNC_ERRORVAL;
+ }
+
+ if (!google::protobuf::python::InitProto2MessageModule(m)) {
+ Py_DECREF(m);
+ return INITFUNC_ERRORVAL;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+ }
+}
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 6f1e3c8b..c4b23c37 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -48,15 +48,15 @@ import re
import six
if six.PY3:
- long = int
+ long = int # pylint: disable=redefined-builtin,invalid-name
+# pylint: disable=g-import-not-at-top
from google.protobuf.internal import type_checkers
from google.protobuf import descriptor
from google.protobuf import text_encoding
-__all__ = ['MessageToString', 'PrintMessage', 'PrintField',
- 'PrintFieldValue', 'Merge']
-
+__all__ = ['MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue',
+ 'Merge']
_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
type_checkers.Int32ValueChecker(),
@@ -67,6 +67,7 @@ _FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
_QUOTES = frozenset(("'", '"'))
+_ANY_FULL_TYPE_NAME = 'google.protobuf.Any'
class Error(Exception):
@@ -74,10 +75,30 @@ class Error(Exception):
class ParseError(Error):
- """Thrown in case of text parsing error."""
+ """Thrown in case of text parsing or tokenizing error."""
+
+ def __init__(self, message=None, line=None, column=None):
+ if message is not None and line is not None:
+ loc = str(line)
+ if column is not None:
+ loc += ':{}'.format(column)
+ message = '{} : {}'.format(loc, message)
+ if message is not None:
+ super(ParseError, self).__init__(message)
+ else:
+ super(ParseError, self).__init__()
+ self._line = line
+ self._column = column
+
+ def GetLine(self):
+ return self._line
+
+ def GetColumn(self):
+ return self._column
class TextWriter(object):
+
def __init__(self, as_utf8):
if six.PY2:
self._writer = io.BytesIO()
@@ -97,9 +118,15 @@ class TextWriter(object):
return self._writer.getvalue()
-def MessageToString(message, as_utf8=False, as_one_line=False,
- pointy_brackets=False, use_index_order=False,
- float_format=None, use_field_number=False):
+def MessageToString(message,
+ as_utf8=False,
+ as_one_line=False,
+ pointy_brackets=False,
+ use_index_order=False,
+ float_format=None,
+ use_field_number=False,
+ descriptor_pool=None,
+ indent=0):
"""Convert protobuf message to text format.
Floating point values can be formatted compactly with 15 digits of
@@ -119,14 +146,16 @@ def MessageToString(message, as_utf8=False, as_one_line=False,
float_format: If set, use this to specify floating point number formatting
(per the "Format Specification Mini-Language"); otherwise, str() is used.
use_field_number: If True, print field numbers instead of names.
+ descriptor_pool: A DescriptorPool used to resolve Any types.
+ indent: The indent level, in terms of spaces, for pretty print.
Returns:
A string of the text formatted protocol buffer message.
"""
out = TextWriter(as_utf8)
- printer = _Printer(out, 0, as_utf8, as_one_line,
- pointy_brackets, use_index_order, float_format,
- use_field_number)
+ printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+ use_index_order, float_format, use_field_number,
+ descriptor_pool)
printer.PrintMessage(message)
result = out.getvalue()
out.close()
@@ -141,39 +170,87 @@ def _IsMapEntry(field):
field.message_type.GetOptions().map_entry)
-def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
- pointy_brackets=False, use_index_order=False,
- float_format=None, use_field_number=False):
- printer = _Printer(out, indent, as_utf8, as_one_line,
- pointy_brackets, use_index_order, float_format,
- use_field_number)
+def PrintMessage(message,
+ out,
+ indent=0,
+ as_utf8=False,
+ as_one_line=False,
+ pointy_brackets=False,
+ use_index_order=False,
+ float_format=None,
+ use_field_number=False,
+ descriptor_pool=None):
+ printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+ use_index_order, float_format, use_field_number,
+ descriptor_pool)
printer.PrintMessage(message)
-def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,
- pointy_brackets=False, use_index_order=False, float_format=None):
+def PrintField(field,
+ value,
+ out,
+ indent=0,
+ as_utf8=False,
+ as_one_line=False,
+ pointy_brackets=False,
+ use_index_order=False,
+ float_format=None):
"""Print a single field name/value pair."""
- printer = _Printer(out, indent, as_utf8, as_one_line,
- pointy_brackets, use_index_order, float_format)
+ printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+ use_index_order, float_format)
printer.PrintField(field, value)
-def PrintFieldValue(field, value, out, indent=0, as_utf8=False,
- as_one_line=False, pointy_brackets=False,
+def PrintFieldValue(field,
+ value,
+ out,
+ indent=0,
+ as_utf8=False,
+ as_one_line=False,
+ pointy_brackets=False,
use_index_order=False,
float_format=None):
"""Print a single field value (not including name)."""
- printer = _Printer(out, indent, as_utf8, as_one_line,
- pointy_brackets, use_index_order, float_format)
+ printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+ use_index_order, float_format)
printer.PrintFieldValue(field, value)
+def _BuildMessageFromTypeName(type_name, descriptor_pool):
+ """Returns a protobuf message instance.
+
+ Args:
+ type_name: Fully-qualified protobuf message type name string.
+ descriptor_pool: DescriptorPool instance.
+
+ Returns:
+ A Message instance of type matching type_name, or None if the a Descriptor
+ wasn't found matching type_name.
+ """
+ # pylint: disable=g-import-not-at-top
+ from google.protobuf import message_factory
+ factory = message_factory.MessageFactory(descriptor_pool)
+ try:
+ message_descriptor = descriptor_pool.FindMessageTypeByName(type_name)
+ except KeyError:
+ return None
+ message_type = factory.GetPrototype(message_descriptor)
+ return message_type()
+
+
class _Printer(object):
"""Text format printer for protocol message."""
- def __init__(self, out, indent=0, as_utf8=False, as_one_line=False,
- pointy_brackets=False, use_index_order=False, float_format=None,
- use_field_number=False):
+ def __init__(self,
+ out,
+ indent=0,
+ as_utf8=False,
+ as_one_line=False,
+ pointy_brackets=False,
+ use_index_order=False,
+ float_format=None,
+ use_field_number=False,
+ descriptor_pool=None):
"""Initialize the Printer.
Floating point values can be formatted compactly with 15 digits of
@@ -195,6 +272,7 @@ class _Printer(object):
(per the "Format Specification Mini-Language"); otherwise, str() is
used.
use_field_number: If True, print field numbers instead of names.
+ descriptor_pool: A DescriptorPool used to resolve Any types.
"""
self.out = out
self.indent = indent
@@ -204,6 +282,20 @@ class _Printer(object):
self.use_index_order = use_index_order
self.float_format = float_format
self.use_field_number = use_field_number
+ self.descriptor_pool = descriptor_pool
+
+ def _TryPrintAsAnyMessage(self, message):
+ """Serializes if message is a google.protobuf.Any field."""
+ packed_message = _BuildMessageFromTypeName(message.TypeName(),
+ self.descriptor_pool)
+ if packed_message:
+ packed_message.MergeFromString(message.value)
+ self.out.write('%s[%s]' % (self.indent * ' ', message.type_url))
+ self._PrintMessageFieldValue(packed_message)
+ self.out.write(' ' if self.as_one_line else '\n')
+ return True
+ else:
+ return False
def PrintMessage(self, message):
"""Convert protobuf message to text format.
@@ -211,6 +303,9 @@ class _Printer(object):
Args:
message: The protocol buffers message.
"""
+ if (message.DESCRIPTOR.full_name == _ANY_FULL_TYPE_NAME and
+ self.descriptor_pool and self._TryPrintAsAnyMessage(message)):
+ return
fields = message.ListFields()
if self.use_index_order:
fields.sort(key=lambda x: x[0].index)
@@ -222,8 +317,8 @@ class _Printer(object):
# of this file to work around.
#
# TODO(haberman): refactor and optimize if this becomes an issue.
- entry_submsg = field.message_type._concrete_class(
- key=key, value=value[key])
+ entry_submsg = field.message_type._concrete_class(key=key,
+ value=value[key])
self.PrintField(field, entry_submsg)
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
for element in value:
@@ -264,6 +359,25 @@ class _Printer(object):
else:
out.write('\n')
+ def _PrintMessageFieldValue(self, value):
+ if self.pointy_brackets:
+ openb = '<'
+ closeb = '>'
+ else:
+ openb = '{'
+ closeb = '}'
+
+ if self.as_one_line:
+ self.out.write(' %s ' % openb)
+ self.PrintMessage(value)
+ self.out.write(closeb)
+ else:
+ self.out.write(' %s\n' % openb)
+ self.indent += 2
+ self.PrintMessage(value)
+ self.indent -= 2
+ self.out.write(' ' * self.indent + closeb)
+
def PrintFieldValue(self, field, value):
"""Print a single field value (not including name).
@@ -274,24 +388,8 @@ class _Printer(object):
value: The value of the field.
"""
out = self.out
- if self.pointy_brackets:
- openb = '<'
- closeb = '>'
- else:
- openb = '{'
- closeb = '}'
-
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
- if self.as_one_line:
- out.write(' %s ' % openb)
- self.PrintMessage(value)
- out.write(closeb)
- else:
- out.write(' %s\n' % openb)
- self.indent += 2
- self.PrintMessage(value)
- self.indent -= 2
- out.write(' ' * self.indent + closeb)
+ self._PrintMessageFieldValue(value)
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
enum_value = field.enum_type.values_by_number.get(value, None)
if enum_value is not None:
@@ -322,9 +420,11 @@ class _Printer(object):
out.write(str(value))
-def Parse(text, message,
- allow_unknown_extension=False, allow_field_number=False):
- """Parses an text representation of a protocol message into a message.
+def Parse(text,
+ message,
+ allow_unknown_extension=False,
+ allow_field_number=False):
+ """Parses a text representation of a protocol message into a message.
Args:
text: Message text representation.
@@ -341,13 +441,16 @@ def Parse(text, message,
"""
if not isinstance(text, str):
text = text.decode('utf-8')
- return ParseLines(text.split('\n'), message, allow_unknown_extension,
- allow_field_number)
+ return ParseLines(
+ text.split('\n'), message, allow_unknown_extension, allow_field_number)
-def Merge(text, message, allow_unknown_extension=False,
- allow_field_number=False):
- """Parses an text representation of a protocol message into a message.
+def Merge(text,
+ message,
+ allow_unknown_extension=False,
+ allow_field_number=False,
+ descriptor_pool=None):
+ """Parses a text representation of a protocol message into a message.
Like Parse(), but allows repeated values for a non-repeated field, and uses
the last one.
@@ -358,6 +461,7 @@ def Merge(text, message, allow_unknown_extension=False,
allow_unknown_extension: if True, skip over missing extensions and keep
parsing
allow_field_number: if True, both field number and field name are allowed.
+ descriptor_pool: A DescriptorPool used to resolve Any types.
Returns:
The same message passed as argument.
@@ -365,13 +469,19 @@ def Merge(text, message, allow_unknown_extension=False,
Raises:
ParseError: On text parsing problems.
"""
- return MergeLines(text.split('\n'), message, allow_unknown_extension,
- allow_field_number)
+ return MergeLines(
+ text.split('\n'),
+ message,
+ allow_unknown_extension,
+ allow_field_number,
+ descriptor_pool=descriptor_pool)
-def ParseLines(lines, message, allow_unknown_extension=False,
+def ParseLines(lines,
+ message,
+ allow_unknown_extension=False,
allow_field_number=False):
- """Parses an text representation of a protocol message into a message.
+ """Parses a text representation of a protocol message into a message.
Args:
lines: An iterable of lines of a message's text representation.
@@ -379,6 +489,7 @@ def ParseLines(lines, message, allow_unknown_extension=False,
allow_unknown_extension: if True, skip over missing extensions and keep
parsing
allow_field_number: if True, both field number and field name are allowed.
+ descriptor_pool: A DescriptorPool used to resolve Any types.
Returns:
The same message passed as argument.
@@ -390,9 +501,12 @@ def ParseLines(lines, message, allow_unknown_extension=False,
return parser.ParseLines(lines, message)
-def MergeLines(lines, message, allow_unknown_extension=False,
- allow_field_number=False):
- """Parses an text representation of a protocol message into a message.
+def MergeLines(lines,
+ message,
+ allow_unknown_extension=False,
+ allow_field_number=False,
+ descriptor_pool=None):
+ """Parses a text representation of a protocol message into a message.
Args:
lines: An iterable of lines of a message's text representation.
@@ -407,41 +521,47 @@ def MergeLines(lines, message, allow_unknown_extension=False,
Raises:
ParseError: On text parsing problems.
"""
- parser = _Parser(allow_unknown_extension, allow_field_number)
+ parser = _Parser(allow_unknown_extension,
+ allow_field_number,
+ descriptor_pool=descriptor_pool)
return parser.MergeLines(lines, message)
class _Parser(object):
"""Text format parser for protocol message."""
- def __init__(self, allow_unknown_extension=False, allow_field_number=False):
+ def __init__(self,
+ allow_unknown_extension=False,
+ allow_field_number=False,
+ descriptor_pool=None):
self.allow_unknown_extension = allow_unknown_extension
self.allow_field_number = allow_field_number
+ self.descriptor_pool = descriptor_pool
def ParseFromString(self, text, message):
- """Parses an text representation of a protocol message into a message."""
+ """Parses a text representation of a protocol message into a message."""
if not isinstance(text, str):
text = text.decode('utf-8')
return self.ParseLines(text.split('\n'), message)
def ParseLines(self, lines, message):
- """Parses an text representation of a protocol message into a message."""
+ """Parses a text representation of a protocol message into a message."""
self._allow_multiple_scalars = False
self._ParseOrMerge(lines, message)
return message
def MergeFromString(self, text, message):
- """Merges an text representation of a protocol message into a message."""
+ """Merges a text representation of a protocol message into a message."""
return self._MergeLines(text.split('\n'), message)
def MergeLines(self, lines, message):
- """Merges an text representation of a protocol message into a message."""
+ """Merges a text representation of a protocol message into a message."""
self._allow_multiple_scalars = True
self._ParseOrMerge(lines, message)
return message
def _ParseOrMerge(self, lines, message):
- """Converts an text representation of a protocol message into a message.
+ """Converts a text representation of a protocol message into a message.
Args:
lines: Lines of a message's text representation.
@@ -450,7 +570,7 @@ class _Parser(object):
Raises:
ParseError: On text parsing problems.
"""
- tokenizer = _Tokenizer(lines)
+ tokenizer = Tokenizer(lines)
while not tokenizer.AtEnd():
self._MergeField(tokenizer, message)
@@ -491,13 +611,13 @@ class _Parser(object):
'Extension "%s" not registered.' % name)
elif message_descriptor != field.containing_type:
raise tokenizer.ParseErrorPreviousToken(
- 'Extension "%s" does not extend message type "%s".' % (
- name, message_descriptor.full_name))
+ 'Extension "%s" does not extend message type "%s".' %
+ (name, message_descriptor.full_name))
tokenizer.Consume(']')
else:
- name = tokenizer.ConsumeIdentifier()
+ name = tokenizer.ConsumeIdentifierOrNumber()
if self.allow_field_number and name.isdigit():
number = ParseInteger(name, True, True)
field = message_descriptor.fields_by_number.get(number, None)
@@ -520,8 +640,8 @@ class _Parser(object):
if not field:
raise tokenizer.ParseErrorPreviousToken(
- 'Message type "%s" has no field named "%s".' % (
- message_descriptor.full_name, name))
+ 'Message type "%s" has no field named "%s".' %
+ (message_descriptor.full_name, name))
if field:
if not self._allow_multiple_scalars and field.containing_oneof:
@@ -532,9 +652,9 @@ class _Parser(object):
if which_oneof is not None and which_oneof != field.name:
raise tokenizer.ParseErrorPreviousToken(
'Field "%s" is specified along with field "%s", another member '
- 'of oneof "%s" for message type "%s".' % (
- field.name, which_oneof, field.containing_oneof.name,
- message_descriptor.full_name))
+ 'of oneof "%s" for message type "%s".' %
+ (field.name, which_oneof, field.containing_oneof.name,
+ message_descriptor.full_name))
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
tokenizer.TryConsume(':')
@@ -543,12 +663,13 @@ class _Parser(object):
tokenizer.Consume(':')
merger = self._MergeScalarField
- if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED
- and tokenizer.TryConsume('[')):
+ if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
+ tokenizer.TryConsume('[')):
# Short repeated format, e.g. "foo: [1, 2, 3]"
while True:
merger(tokenizer, message, field)
- if tokenizer.TryConsume(']'): break
+ if tokenizer.TryConsume(']'):
+ break
tokenizer.Consume(',')
else:
@@ -563,6 +684,21 @@ class _Parser(object):
if not tokenizer.TryConsume(','):
tokenizer.TryConsume(';')
+ def _ConsumeAnyTypeUrl(self, tokenizer):
+ """Consumes a google.protobuf.Any type URL and returns the type name."""
+ # Consume "type.googleapis.com/".
+ tokenizer.ConsumeIdentifier()
+ tokenizer.Consume('.')
+ tokenizer.ConsumeIdentifier()
+ tokenizer.Consume('.')
+ tokenizer.ConsumeIdentifier()
+ tokenizer.Consume('/')
+ # Consume the fully-qualified type name.
+ name = [tokenizer.ConsumeIdentifier()]
+ while tokenizer.TryConsume('.'):
+ name.append(tokenizer.ConsumeIdentifier())
+ return '.'.join(name)
+
def _MergeMessageField(self, tokenizer, message, field):
"""Merges a single scalar field into a message.
@@ -582,7 +718,34 @@ class _Parser(object):
tokenizer.Consume('{')
end_token = '}'
- if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ if (field.message_type.full_name == _ANY_FULL_TYPE_NAME and
+ tokenizer.TryConsume('[')):
+ packed_type_name = self._ConsumeAnyTypeUrl(tokenizer)
+ tokenizer.Consume(']')
+ tokenizer.TryConsume(':')
+ if tokenizer.TryConsume('<'):
+ expanded_any_end_token = '>'
+ else:
+ tokenizer.Consume('{')
+ expanded_any_end_token = '}'
+ if not self.descriptor_pool:
+ raise ParseError('Descriptor pool required to parse expanded Any field')
+ expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name,
+ self.descriptor_pool)
+ if not expanded_any_sub_message:
+ raise ParseError('Type %s not found in descriptor pool' %
+ packed_type_name)
+ while not tokenizer.TryConsume(expanded_any_end_token):
+ if tokenizer.AtEnd():
+ raise tokenizer.ParseErrorPreviousToken('Expected "%s".' %
+ (expanded_any_end_token,))
+ self._MergeField(tokenizer, expanded_any_sub_message)
+ if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ any_message = getattr(message, field.name).add()
+ else:
+ any_message = getattr(message, field.name)
+ any_message.Pack(expanded_any_sub_message)
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
if field.is_extension:
sub_message = message.Extensions[field].add()
elif is_map_entry:
@@ -628,17 +791,17 @@ class _Parser(object):
if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
descriptor.FieldDescriptor.TYPE_SINT32,
descriptor.FieldDescriptor.TYPE_SFIXED32):
- value = tokenizer.ConsumeInt32()
+ value = _ConsumeInt32(tokenizer)
elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
descriptor.FieldDescriptor.TYPE_SINT64,
descriptor.FieldDescriptor.TYPE_SFIXED64):
- value = tokenizer.ConsumeInt64()
+ value = _ConsumeInt64(tokenizer)
elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
descriptor.FieldDescriptor.TYPE_FIXED32):
- value = tokenizer.ConsumeUint32()
+ value = _ConsumeUint32(tokenizer)
elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
descriptor.FieldDescriptor.TYPE_FIXED64):
- value = tokenizer.ConsumeUint64()
+ value = _ConsumeUint64(tokenizer)
elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
descriptor.FieldDescriptor.TYPE_DOUBLE):
value = tokenizer.ConsumeFloat()
@@ -753,13 +916,12 @@ def _SkipFieldValue(tokenizer):
return
if (not tokenizer.TryConsumeIdentifier() and
- not tokenizer.TryConsumeInt64() and
- not tokenizer.TryConsumeUint64() and
+ not _TryConsumeInt64(tokenizer) and not _TryConsumeUint64(tokenizer) and
not tokenizer.TryConsumeFloat()):
raise ParseError('Invalid field value: ' + tokenizer.token)
-class _Tokenizer(object):
+class Tokenizer(object):
"""Protocol buffer text representation tokenizer.
This class handles the lower level string parsing by splitting it into
@@ -768,17 +930,20 @@ class _Tokenizer(object):
It was directly ported from the Java protocol buffer API.
"""
- _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
+ _WHITESPACE = re.compile(r'\s+')
+ _COMMENT = re.compile(r'(\s*#.*$)', re.MULTILINE)
+ _WHITESPACE_OR_COMMENT = re.compile(r'(\s|(#.*$))+', re.MULTILINE)
_TOKEN = re.compile('|'.join([
- r'[a-zA-Z_][0-9a-zA-Z_+-]*', # an identifier
+ r'[a-zA-Z_][0-9a-zA-Z_+-]*', # an identifier
r'([0-9+-]|(\.[0-9]))[0-9a-zA-Z_.+-]*', # a number
- ] + [ # quoted str for each quote mark
+ ] + [ # quoted str for each quote mark
r'{qt}([^{qt}\n\\]|\\.)*({qt}|\\?$)'.format(qt=mark) for mark in _QUOTES
]))
- _IDENTIFIER = re.compile(r'\w+')
+ _IDENTIFIER = re.compile(r'[^\d\W]\w*')
+ _IDENTIFIER_OR_NUMBER = re.compile(r'\w+')
- def __init__(self, lines):
+ def __init__(self, lines, skip_comments=True):
self._position = 0
self._line = -1
self._column = 0
@@ -789,6 +954,9 @@ class _Tokenizer(object):
self._previous_line = 0
self._previous_column = 0
self._more_lines = True
+ self._skip_comments = skip_comments
+ self._whitespace_pattern = (skip_comments and self._WHITESPACE_OR_COMMENT
+ or self._WHITESPACE)
self._SkipWhitespace()
self.NextToken()
@@ -818,7 +986,7 @@ class _Tokenizer(object):
def _SkipWhitespace(self):
while True:
self._PopLine()
- match = self._WHITESPACE.match(self._current_line, self._column)
+ match = self._whitespace_pattern.match(self._current_line, self._column)
if not match:
break
length = len(match.group(0))
@@ -848,7 +1016,14 @@ class _Tokenizer(object):
ParseError: If the text couldn't be consumed.
"""
if not self.TryConsume(token):
- raise self._ParseError('Expected "%s".' % token)
+ raise self.ParseError('Expected "%s".' % token)
+
+ def ConsumeComment(self):
+ result = self.token
+ if not self._COMMENT.match(result):
+ raise self.ParseError('Expected comment.')
+ self.NextToken()
+ return result
def TryConsumeIdentifier(self):
try:
@@ -868,85 +1043,55 @@ class _Tokenizer(object):
"""
result = self.token
if not self._IDENTIFIER.match(result):
- raise self._ParseError('Expected identifier.')
+ raise self.ParseError('Expected identifier.')
self.NextToken()
return result
- def ConsumeInt32(self):
- """Consumes a signed 32bit integer number.
-
- Returns:
- The integer parsed.
-
- Raises:
- ParseError: If a signed 32bit integer couldn't be consumed.
- """
+ def TryConsumeIdentifierOrNumber(self):
try:
- result = ParseInteger(self.token, is_signed=True, is_long=False)
- except ValueError as e:
- raise self._ParseError(str(e))
- self.NextToken()
- return result
-
- def ConsumeUint32(self):
- """Consumes an unsigned 32bit integer number.
-
- Returns:
- The integer parsed.
-
- Raises:
- ParseError: If an unsigned 32bit integer couldn't be consumed.
- """
- try:
- result = ParseInteger(self.token, is_signed=False, is_long=False)
- except ValueError as e:
- raise self._ParseError(str(e))
- self.NextToken()
- return result
-
- def TryConsumeInt64(self):
- try:
- self.ConsumeInt64()
+ self.ConsumeIdentifierOrNumber()
return True
except ParseError:
return False
- def ConsumeInt64(self):
- """Consumes a signed 64bit integer number.
+ def ConsumeIdentifierOrNumber(self):
+ """Consumes protocol message field identifier.
Returns:
- The integer parsed.
+ Identifier string.
Raises:
- ParseError: If a signed 64bit integer couldn't be consumed.
+ ParseError: If an identifier couldn't be consumed.
"""
- try:
- result = ParseInteger(self.token, is_signed=True, is_long=True)
- except ValueError as e:
- raise self._ParseError(str(e))
+ result = self.token
+ if not self._IDENTIFIER_OR_NUMBER.match(result):
+ raise self.ParseError('Expected identifier or number.')
self.NextToken()
return result
- def TryConsumeUint64(self):
+ def TryConsumeInteger(self):
try:
- self.ConsumeUint64()
+ # Note: is_long only affects value type, not whether an error is raised.
+ self.ConsumeInteger()
return True
except ParseError:
return False
- def ConsumeUint64(self):
- """Consumes an unsigned 64bit integer number.
+ def ConsumeInteger(self, is_long=False):
+ """Consumes an integer number.
+ Args:
+ is_long: True if the value should be returned as a long integer.
Returns:
The integer parsed.
Raises:
- ParseError: If an unsigned 64bit integer couldn't be consumed.
+ ParseError: If an integer couldn't be consumed.
"""
try:
- result = ParseInteger(self.token, is_signed=False, is_long=True)
+ result = _ParseAbstractInteger(self.token, is_long=is_long)
except ValueError as e:
- raise self._ParseError(str(e))
+ raise self.ParseError(str(e))
self.NextToken()
return result
@@ -969,7 +1114,7 @@ class _Tokenizer(object):
try:
result = ParseFloat(self.token)
except ValueError as e:
- raise self._ParseError(str(e))
+ raise self.ParseError(str(e))
self.NextToken()
return result
@@ -985,7 +1130,7 @@ class _Tokenizer(object):
try:
result = ParseBool(self.token)
except ValueError as e:
- raise self._ParseError(str(e))
+ raise self.ParseError(str(e))
self.NextToken()
return result
@@ -1039,15 +1184,15 @@ class _Tokenizer(object):
"""
text = self.token
if len(text) < 1 or text[0] not in _QUOTES:
- raise self._ParseError('Expected string but found: %r' % (text,))
+ raise self.ParseError('Expected string but found: %r' % (text,))
if len(text) < 2 or text[-1] != text[0]:
- raise self._ParseError('String missing ending quote: %r' % (text,))
+ raise self.ParseError('String missing ending quote: %r' % (text,))
try:
result = text_encoding.CUnescape(text[1:-1])
except ValueError as e:
- raise self._ParseError(str(e))
+ raise self.ParseError(str(e))
self.NextToken()
return result
@@ -1055,7 +1200,7 @@ class _Tokenizer(object):
try:
result = ParseEnum(field, self.token)
except ValueError as e:
- raise self._ParseError(str(e))
+ raise self.ParseError(str(e))
self.NextToken()
return result
@@ -1068,16 +1213,15 @@ class _Tokenizer(object):
Returns:
A ParseError instance.
"""
- return ParseError('%d:%d : %s' % (
- self._previous_line + 1, self._previous_column + 1, message))
+ return ParseError(message, self._previous_line + 1,
+ self._previous_column + 1)
- def _ParseError(self, message):
+ def ParseError(self, message):
"""Creates and *returns* a ParseError for the current token."""
- return ParseError('%d:%d : %s' % (
- self._line + 1, self._column + 1, message))
+ return ParseError(message, self._line + 1, self._column + 1)
def _StringParseError(self, e):
- return self._ParseError('Couldn\'t parse string: ' + str(e))
+ return self.ParseError('Couldn\'t parse string: ' + str(e))
def NextToken(self):
"""Reads the next meaningful token."""
@@ -1092,12 +1236,124 @@ class _Tokenizer(object):
return
match = self._TOKEN.match(self._current_line, self._column)
+ if not match and not self._skip_comments:
+ match = self._COMMENT.match(self._current_line, self._column)
if match:
token = match.group(0)
self.token = token
else:
self.token = self._current_line[self._column]
+# Aliased so it can still be accessed by current visibility violators.
+# TODO(dbarnett): Migrate violators to textformat_tokenizer.
+_Tokenizer = Tokenizer # pylint: disable=invalid-name
+
+
+def _ConsumeInt32(tokenizer):
+ """Consumes a signed 32bit integer number from tokenizer.
+
+ Args:
+ tokenizer: A tokenizer used to parse the number.
+
+ Returns:
+ The integer parsed.
+
+ Raises:
+ ParseError: If a signed 32bit integer couldn't be consumed.
+ """
+ return _ConsumeInteger(tokenizer, is_signed=True, is_long=False)
+
+
+def _ConsumeUint32(tokenizer):
+ """Consumes an unsigned 32bit integer number from tokenizer.
+
+ Args:
+ tokenizer: A tokenizer used to parse the number.
+
+ Returns:
+ The integer parsed.
+
+ Raises:
+ ParseError: If an unsigned 32bit integer couldn't be consumed.
+ """
+ return _ConsumeInteger(tokenizer, is_signed=False, is_long=False)
+
+
+def _TryConsumeInt64(tokenizer):
+ try:
+ _ConsumeInt64(tokenizer)
+ return True
+ except ParseError:
+ return False
+
+
+def _ConsumeInt64(tokenizer):
+ """Consumes a signed 32bit integer number from tokenizer.
+
+ Args:
+ tokenizer: A tokenizer used to parse the number.
+
+ Returns:
+ The integer parsed.
+
+ Raises:
+ ParseError: If a signed 32bit integer couldn't be consumed.
+ """
+ return _ConsumeInteger(tokenizer, is_signed=True, is_long=True)
+
+
+def _TryConsumeUint64(tokenizer):
+ try:
+ _ConsumeUint64(tokenizer)
+ return True
+ except ParseError:
+ return False
+
+
+def _ConsumeUint64(tokenizer):
+ """Consumes an unsigned 64bit integer number from tokenizer.
+
+ Args:
+ tokenizer: A tokenizer used to parse the number.
+
+ Returns:
+ The integer parsed.
+
+ Raises:
+ ParseError: If an unsigned 64bit integer couldn't be consumed.
+ """
+ return _ConsumeInteger(tokenizer, is_signed=False, is_long=True)
+
+
+def _TryConsumeInteger(tokenizer, is_signed=False, is_long=False):
+ try:
+ _ConsumeInteger(tokenizer, is_signed=is_signed, is_long=is_long)
+ return True
+ except ParseError:
+ return False
+
+
+def _ConsumeInteger(tokenizer, is_signed=False, is_long=False):
+ """Consumes an integer number from tokenizer.
+
+ Args:
+ tokenizer: A tokenizer used to parse the number.
+ is_signed: True if a signed integer must be parsed.
+ is_long: True if a long integer must be parsed.
+
+ Returns:
+ The integer parsed.
+
+ Raises:
+ ParseError: If an integer with given characteristics couldn't be consumed.
+ """
+ try:
+ result = ParseInteger(tokenizer.token, is_signed=is_signed, is_long=is_long)
+ except ValueError as e:
+ raise tokenizer.ParseError(str(e))
+ tokenizer.NextToken()
+ return result
+
def ParseInteger(text, is_signed=False, is_long=False):
"""Parses an integer.
@@ -1114,22 +1370,39 @@ def ParseInteger(text, is_signed=False, is_long=False):
ValueError: Thrown Iff the text is not a valid integer.
"""
# Do the actual parsing. Exception handling is propagated to caller.
+ result = _ParseAbstractInteger(text, is_long=is_long)
+
+ # Check if the integer is sane. Exceptions handled by callers.
+ checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
+ checker.CheckValue(result)
+ return result
+
+
+def _ParseAbstractInteger(text, is_long=False):
+ """Parses an integer without checking size/signedness.
+
+ Args:
+ text: The text to parse.
+ is_long: True if the value should be returned as a long integer.
+
+ Returns:
+ The integer value.
+
+ Raises:
+ ValueError: Thrown Iff the text is not a valid integer.
+ """
+ # Do the actual parsing. Exception handling is propagated to caller.
try:
# We force 32-bit values to int and 64-bit values to long to make
# alternate implementations where the distinction is more significant
# (e.g. the C++ implementation) simpler.
if is_long:
- result = long(text, 0)
+ return long(text, 0)
else:
- result = int(text, 0)
+ return int(text, 0)
except ValueError:
raise ValueError('Couldn\'t parse integer: %s' % text)
- # Check if the integer is sane. Exceptions handled by callers.
- checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
- checker.CheckValue(result)
- return result
-
def ParseFloat(text):
"""Parse a floating point number.
@@ -1206,14 +1479,12 @@ def ParseEnum(field, value):
# Identifier.
enum_value = enum_descriptor.values_by_name.get(value, None)
if enum_value is None:
- raise ValueError(
- 'Enum type "%s" has no value named %s.' % (
- enum_descriptor.full_name, value))
+ raise ValueError('Enum type "%s" has no value named %s.' %
+ (enum_descriptor.full_name, value))
else:
# Numeric value.
enum_value = enum_descriptor.values_by_number.get(number, None)
if enum_value is None:
- raise ValueError(
- 'Enum type "%s" has no value with number %d.' % (
- enum_descriptor.full_name, number))
+ raise ValueError('Enum type "%s" has no value with number %d.' %
+ (enum_descriptor.full_name, number))
return enum_value.number
diff --git a/python/setup.py b/python/setup.py
index 76f0cbc8..524a312f 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -76,6 +76,7 @@ def generate_proto(source, require = True):
sys.exit(-1)
def GenerateUnittestProtos():
+ generate_proto("../src/google/protobuf/any_test.proto", False)
generate_proto("../src/google/protobuf/map_unittest.proto", False)
generate_proto("../src/google/protobuf/unittest_arena.proto", False)
generate_proto("../src/google/protobuf/unittest_no_arena.proto", False)
@@ -94,6 +95,7 @@ def GenerateUnittestProtos():
generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
generate_proto("google/protobuf/internal/factory_test1.proto", False)
generate_proto("google/protobuf/internal/factory_test2.proto", False)
+ generate_proto("google/protobuf/internal/file_options_test.proto", False)
generate_proto("google/protobuf/internal/import_test_package/inner.proto", False)
generate_proto("google/protobuf/internal/import_test_package/outer.proto", False)
generate_proto("google/protobuf/internal/missing_enum_values.proto", False)
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index fbde4a6d..c91faa08 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -283,8 +283,8 @@ void Any::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Any)
}
-::google::protobuf::uint8* Any::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Any::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
// optional string type_url = 1;
if (this->type_url().size() > 0) {
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 100a67f6..d8cbee2d 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -42,7 +42,7 @@ class Any;
// ===================================================================
-class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
public:
Any();
virtual ~Any();
@@ -86,7 +86,11 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
index 45db6ede..81dcf46c 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -65,6 +65,16 @@ option objc_class_prefix = "GPB";
// foo = any.unpack(Foo.class);
// }
//
+// Example 3: Pack and unpack a message in Python.
+//
+// foo = Foo(...)
+// any = Any()
+// any.Pack(foo)
+// ...
+// if any.Is(Foo.DESCRIPTOR):
+// any.Unpack(foo)
+// ...
+//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
@@ -104,10 +114,10 @@ message Any {
// A URL/resource name whose content describes the type of the
// serialized protocol buffer message.
//
- // For URLs which use the schema `http`, `https`, or no schema, the
+ // For URLs which use the scheme `http`, `https`, or no scheme, the
// following restrictions and interpretations apply:
//
- // * If no schema is provided, `https` is assumed.
+ // * If no scheme is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// The name should be in a canonical form (e.g., leading "." is
@@ -120,7 +130,7 @@ message Any {
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
- // Schemas other than `http`, `https` (or the empty schema) might be
+ // Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index cbeba302..d5dd8923 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -475,8 +475,8 @@ void Api::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Api)
}
-::google::protobuf::uint8* Api::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Api::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -492,15 +492,15 @@ void Api::SerializeWithCachedSizes(
// repeated .google.protobuf.Method methods = 2;
for (unsigned int i = 0, n = this->methods_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->methods(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->methods(i), false, target);
}
// repeated .google.protobuf.Option options = 3;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, this->options(i), false, target);
}
// optional string version = 4;
@@ -517,15 +517,15 @@ void Api::SerializeWithCachedSizes(
// optional .google.protobuf.SourceContext source_context = 5;
if (this->has_source_context()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 5, *this->source_context_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 5, *this->source_context_, false, target);
}
// repeated .google.protobuf.Mixin mixins = 6;
for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 6, this->mixins(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 6, this->mixins(i), false, target);
}
// optional .google.protobuf.Syntax syntax = 7;
@@ -1225,8 +1225,8 @@ void Method::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Method)
}
-::google::protobuf::uint8* Method::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Method::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -1274,8 +1274,8 @@ void Method::SerializeWithCachedSizes(
// repeated .google.protobuf.Option options = 6;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 6, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 6, this->options(i), false, target);
}
// optional .google.protobuf.Syntax syntax = 7;
@@ -1803,8 +1803,8 @@ void Mixin::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Mixin)
}
-::google::protobuf::uint8* Mixin::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Mixin::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
// optional string name = 1;
if (this->name().size() > 0) {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index bb35e471..c9ec923a 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -45,7 +45,7 @@ class Mixin;
// ===================================================================
-class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Api) */ {
public:
Api();
virtual ~Api();
@@ -79,7 +79,11 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -196,7 +200,7 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Method) */ {
public:
Method();
virtual ~Method();
@@ -230,7 +234,11 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -337,7 +345,7 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Mixin) */ {
public:
Mixin();
virtual ~Mixin();
@@ -371,7 +379,11 @@ class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 613e5897..78e20946 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -133,12 +133,7 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
b->pos = kHeaderSize + n;
b->size = size;
- if (b->avail() == 0) {
- // Do not attempt to reuse this block.
- b->owner = NULL;
- } else {
- b->owner = me;
- }
+ b->owner = me;
#ifdef ADDRESS_SANITIZER
// Poison the rest of the block for ASAN. It was unpoisoned by the underlying
// malloc but it's not yet usable until we return it as part of an allocation.
@@ -223,9 +218,7 @@ void* Arena::SlowAlloc(size_t n) {
}
b = NewBlock(me, b, n, options_.start_block_size, options_.max_block_size);
AddBlock(b);
- if (b->owner == me) { // If this block can be reused (see NewBlock()).
- SetThreadCacheBlock(b);
- }
+ SetThreadCacheBlock(b);
return reinterpret_cast<char*>(b) + kHeaderSize;
}
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index cf07b9fc..58b1e126 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -801,7 +801,7 @@ class LIBPROTOBUF_EXPORT Arena {
template <typename T>
static void CreateInArenaStorageInternal(
T* ptr, Arena* arena, google::protobuf::internal::false_type) {
- new (ptr) T;
+ new (ptr) T();
}
template <typename T>
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index ab25ffe1..5f33e939 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -42,7 +42,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/arena_test_util.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/unittest.pb.h>
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index c1a6c15d..df6f8afc 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -641,18 +641,23 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
return;
}
- // Seek backwards to the beginning of the line, which is where we will
- // insert the data. Note that this has the effect of pushing the insertion
- // point down, so the data is inserted before it. This is intentional
- // because it means that multiple insertions at the same point will end
- // up in the expected order in the final output.
- pos = target->find_last_of('\n', pos);
- if (pos == string::npos) {
- // Insertion point is on the first line.
- pos = 0;
+ if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) {
+ // Support for inline "/* @@protoc_insertion_point() */"
+ pos = pos - 3;
} else {
- // Advance to character after '\n'.
- ++pos;
+ // Seek backwards to the beginning of the line, which is where we will
+ // insert the data. Note that this has the effect of pushing the
+ // insertion point down, so the data is inserted before it. This is
+ // intentional because it means that multiple insertions at the same point
+ // will end up in the expected order in the final output.
+ pos = target->find_last_of('\n', pos);
+ if (pos == string::npos) {
+ // Insertion point is on the first line.
+ pos = 0;
+ } else {
+ // Advance to character after '\n'.
+ ++pos;
+ }
}
// Extract indent.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 10252b39..ffd81529 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -35,8 +35,8 @@
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index f585c31b..dd9f1887 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -182,33 +182,33 @@ GenerateConstructorCode(io::Printer* printer) const {
void MapFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
+ const FieldDescriptor* key_field =
+ descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_field =
descriptor_->message_type()->FindFieldByName("value");
- printer->Print(variables_,
- "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
-
+ bool using_entry = false;
+ string key;
+ string value;
if (IsProto3Field(descriptor_) ||
value_field->type() != FieldDescriptor::TYPE_ENUM) {
printer->Print(variables_,
+ "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ >,\n"
+ " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
+ " parser(&$name$_);\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
- " input, entry.get()));\n");
- switch (value_field->cpp_type()) {
- case FieldDescriptor::CPPTYPE_MESSAGE:
- printer->Print(variables_,
- "(*mutable_$name$())[entry->key()].Swap("
- "entry->mutable_value());\n");
- break;
- case FieldDescriptor::CPPTYPE_ENUM:
- printer->Print(variables_,
- "(*mutable_$name$())[entry->key()] =\n"
- " static_cast< $val_cpp$ >(*entry->mutable_value());\n");
- break;
- default:
- printer->Print(variables_,
- "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
- break;
- }
+ " input, &parser));\n");
+ key = "parser.key()";
+ value = "parser.value()";
} else {
+ using_entry = true;
+ key = "entry->key()";
+ value = "entry->value()";
+ printer->Print(variables_,
+ "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
printer->Print(variables_,
"{\n"
" ::std::string data;\n"
@@ -229,28 +229,23 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" unknown_fields_stream.WriteString(data);\n");
}
-
printer->Print(variables_,
" }\n"
"}\n");
}
- const FieldDescriptor* key_field =
- descriptor_->message_type()->FindFieldByName("key");
if (key_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
- key_field, options_, true, variables_,
- "entry->key().data(), entry->key().length(),\n", printer);
+ key_field, options_, true, variables_,
+ StrCat(key, ".data(), ", key, ".length(),\n").data(), printer);
}
if (value_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(value_field, options_, true, variables_,
- "entry->mutable_value()->data(),\n"
- "entry->mutable_value()->length(),\n",
- printer);
+ StrCat(value, ".data(), ", value, ".length(),\n").data(), printer);
}
// If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
+ if (using_entry && SupportsArenas(descriptor_)) {
printer->Print(variables_,
"if (entry->GetArena() != NULL) entry.release();\n");
}
@@ -333,8 +328,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
- " Write$declared_type$NoVirtualToArray(\n"
- " $number$, *entry, target);\n");
+ " InternalWrite$declared_type$NoVirtualToArray(\n"
+ " $number$, *entry, false, target);\n");
printer->Indent();
printer->Indent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index da2a4c92..32f63152 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -838,11 +838,13 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+ vars["full_name"] = descriptor_->full_name();
vars["superclass"] = SuperClassName(descriptor_, options_);
printer->Print(vars,
"template <class T>\n"
- "class $classname$ : public $superclass$ {\n"
+ "class $classname$ : public $superclass$ "
+ "/* @@protoc_insertion_point(dep_base_class_definition:$full_name$) */ {\n"
" public:\n");
printer->Indent();
@@ -878,6 +880,7 @@ GenerateClassDefinition(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
+ vars["full_name"] = descriptor_->full_name();
vars["field_count"] = SimpleItoa(descriptor_->field_count());
vars["oneof_decl_count"] = SimpleItoa(descriptor_->oneof_decl_count());
if (options_.dllexport_decl.empty()) {
@@ -892,7 +895,9 @@ GenerateClassDefinition(io::Printer* printer) {
vars["superclass"] = SuperClassName(descriptor_, options_);
}
printer->Print(vars,
- "class $dllexport$$classname$ : public $superclass$ {\n");
+ "class $dllexport$$classname$ : public $superclass$ "
+ "/* @@protoc_insertion_point(class_definition:$full_name$) */ "
+ "{\n");
printer->Annotate("classname", descriptor_);
if (use_dependent_base_) {
printer->Print(vars, " friend class $superclass$;\n");
@@ -1076,7 +1081,11 @@ GenerateClassDefinition(io::Printer* printer) {
}
if (HasFastArraySerialization(descriptor_->file(), options_)) {
printer->Print(
- "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
+ "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
+ " bool deterministic, ::google::protobuf::uint8* output) const;\n"
+ "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {\n"
+ " return InternalSerializeWithCachedSizesToArray(false, output);\n"
+ "}\n");
}
}
@@ -1095,6 +1104,13 @@ GenerateClassDefinition(io::Printer* printer) {
descriptors.push_back(descriptor_->oneof_decl(i)->field(j));
}
}
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ const Descriptor* nested_type = descriptor_->nested_type(i);
+ if (IsMapEntryMessage(nested_type)) {
+ descriptors.push_back(nested_type->FindFieldByName("key"));
+ descriptors.push_back(nested_type->FindFieldByName("value"));
+ }
+ }
uses_string_ = false;
if (PreserveUnknownFields(descriptor_) &&
!UseUnknownFieldSet(descriptor_->file(), options_)) {
@@ -3267,8 +3283,8 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
"// Extension range [$start$, $end$)\n");
if (to_array) {
printer->Print(vars,
- "target = _extensions_.SerializeWithCachedSizesToArray(\n"
- " $start$, $end$, target);\n\n");
+ "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n"
+ " $start$, $end$, false, target);\n\n");
} else {
printer->Print(vars,
"_extensions_.SerializeWithCachedSizes(\n"
@@ -3320,10 +3336,11 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
printer->Print(
- "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
- " ::google::protobuf::uint8* target) const {\n"
- " target =\n"
- " _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
+ "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n"
+ " bool deterministic, ::google::protobuf::uint8* target) const {\n"
+ " target = _extensions_."
+ "InternalSerializeMessageSetWithCachedSizesToArray(\n"
+ " deterministic, target);\n",
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
printer->Print(
@@ -3337,8 +3354,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
}
printer->Print(
- "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
- " ::google::protobuf::uint8* target) const {\n",
+ "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n"
+ " bool deterministic, ::google::protobuf::uint8* target) const {\n",
"classname", classname_);
printer->Indent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 332c0264..d021035d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -520,8 +520,8 @@ void MessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
- " Write$declared_type$NoVirtualToArray(\n"
- " $number$, *$non_null_ptr_to_name$, target);\n");
+ " InternalWrite$declared_type$NoVirtualToArray(\n"
+ " $number$, *$non_null_ptr_to_name$, false, target);\n");
}
void MessageFieldGenerator::
@@ -1033,8 +1033,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
- " Write$declared_type$NoVirtualToArray(\n"
- " $number$, this->$name$(i), target);\n"
+ " InternalWrite$declared_type$NoVirtualToArray(\n"
+ " $number$, this->$name$(i), false, target);\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index ab1d2ed3..ee44fb0a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -46,12 +46,14 @@ struct Options {
Options()
: safe_boundary_check(false),
proto_h(false),
+ allow_import_public(true),
annotate_headers(false),
enforce_lite(false) {}
string dllexport_decl;
bool safe_boundary_check;
bool proto_h;
+ bool allow_import_public;
bool annotate_headers;
bool enforce_lite;
string annotation_pragma_name;
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index 0a112888..6cfa14a0 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -42,8 +42,8 @@ namespace protobuf {
namespace compiler {
namespace java {
-Context::Context(const FileDescriptor* file)
- : name_resolver_(new ClassNameResolver), enforce_lite_(false) {
+Context::Context(const FileDescriptor* file, const Options& options)
+ : name_resolver_(new ClassNameResolver), options_(options) {
InitializeFieldGeneratorInfo(file);
}
@@ -192,8 +192,8 @@ const OneofGeneratorInfo* Context::GetOneofGeneratorInfo(
// Does this message class have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
- return enforce_lite_ || descriptor->file()->options().optimize_for() !=
- FileOptions::CODE_SIZE;
+ return options_.enforce_lite ||
+ descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
}
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
index a480e45d..f92ae87e 100644
--- a/src/google/protobuf/compiler/java/java_context.h
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -39,6 +39,7 @@
#include <vector>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
namespace google {
namespace protobuf {
@@ -64,7 +65,7 @@ struct OneofGeneratorInfo;
// generators.
class Context {
public:
- explicit Context(const FileDescriptor* file);
+ Context(const FileDescriptor* file, const Options& options);
~Context();
// Get the name resolver associated with this context. The resolver
@@ -79,15 +80,12 @@ class Context {
const OneofGeneratorInfo* GetOneofGeneratorInfo(
const OneofDescriptor* oneof) const;
+ const Options& options() const { return options_; }
+
// Enforces all the files (including transitive dependencies) to use
// LiteRuntime.
- void SetEnforceLite(bool enforce_lite) {
- enforce_lite_ = enforce_lite;
- }
- bool EnforceLite() const {
- return enforce_lite_;
- }
+ bool EnforceLite() const { return options_.enforce_lite; }
// Does this message class have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
@@ -102,7 +100,7 @@ class Context {
google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
- bool enforce_lite_;
+ Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
};
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 947b80e4..b46cfe9c 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -86,10 +86,12 @@ EnumGenerator::~EnumGenerator() {}
void EnumGenerator::Generate(io::Printer* printer) {
WriteEnumDocComment(printer, descriptor_);
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.ProtocolMessageEnum {\n",
- "classname", descriptor_->name());
+ "public enum $classname$\n"
+ " implements com.google.protobuf.ProtocolMessageEnum {\n",
+ "classname", descriptor_->name());
+ printer->Annotate("classname", descriptor_);
printer->Indent();
bool ordinal_is_index = true;
diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h
index a0d91f5a..c33e713d 100644
--- a/src/google/protobuf/compiler/java/java_enum.h
+++ b/src/google/protobuf/compiler/java/java_enum.h
@@ -58,9 +58,8 @@ namespace java {
class EnumGenerator {
public:
- explicit EnumGenerator(const EnumDescriptor* descriptor,
- bool immutable_api,
- Context* context);
+ EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api,
+ Context* context);
~EnumGenerator();
void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 3e54be3d..2e916c56 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -76,6 +76,11 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
(*variables)["on_changed"] = "onChanged();";
+ // Use deprecated valueOf() method to be compatible with old generated code
+ // for v2.5.0/v2.6.1.
+ // TODO(xiaofeng): Use "forNumber" when we no longer support compatibility
+ // with v2.5.0/v2.6.1.
+ (*variables)["for_number"] = "valueOf";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -191,7 +196,7 @@ GenerateMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
- " $type$ result = $type$.forNumber($name$_);\n"
+ " $type$ result = $type$.$for_number$($name$_);\n"
" return result == null ? $unknown$ : result;\n"
"}\n");
}
@@ -224,7 +229,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
- " $type$ result = $type$.forNumber($name$_);\n"
+ " $type$ result = $type$.$for_number$($name$_);\n"
" return result == null ? $unknown$ : result;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
@@ -304,7 +309,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.forNumber(rawValue);\n"
+ "$type$ value = $type$.$for_number$(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -398,7 +403,8 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" if ($has_oneof_case_message$) {\n"
- " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+ " $type$ result = $type$.$for_number$(\n"
+ " (java.lang.Integer) $oneof_name$_);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" return $default$;\n"
@@ -436,7 +442,8 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
" if ($has_oneof_case_message$) {\n"
- " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+ " $type$ result = $type$.$for_number$(\n"
+ " (java.lang.Integer) $oneof_name$_);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" return $default$;\n"
@@ -493,7 +500,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.forNumber(rawValue);\n"
+ "$type$ value = $type$.$for_number$(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -606,7 +613,7 @@ GenerateMembers(io::Printer* printer) const {
" new com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$>() {\n"
" public $type$ convert(java.lang.Integer from) {\n"
- " $type$ result = $type$.forNumber(from);\n"
+ " $type$ result = $type$.$for_number$(from);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" };\n");
@@ -839,7 +846,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
- "$type$ value = $type$.forNumber(rawValue);\n"
+ "$type$ value = $type$.$for_number$(rawValue);\n"
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
@@ -887,8 +894,8 @@ GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->is_packed()) {
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ " output.writeUInt32NoTag($tag$);\n"
+ " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.writeEnumNoTag($name$_.get(i));\n"
@@ -920,7 +927,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"if (!get$capitalized_name$List().isEmpty()) {"
" size += $tag_size$;\n"
" size += com.google.protobuf.CodedOutputStream\n"
- " .computeRawVarint32Size(dataSize);\n"
+ " .computeUInt32SizeNoTag(dataSize);\n"
"}");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index 908d6db4..aa0eb5e8 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -258,7 +258,9 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
void ImmutableEnumFieldLiteGenerator::
GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_ = $default_number$;\n");
+ if (!IsDefaultValueJavaDefault(descriptor_)) {
+ printer->Print(variables_, "$name$_ = $default_number$;\n");
+ }
}
void ImmutableEnumFieldLiteGenerator::
@@ -885,8 +887,8 @@ GenerateSerializationCode(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ " output.writeUInt32NoTag($tag$);\n"
+ " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.writeEnumNoTag($name$_.getInt(i));\n"
@@ -918,7 +920,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"if (!get$capitalized_name$List().isEmpty()) {"
" size += $tag_size$;\n"
" size += com.google.protobuf.CodedOutputStream\n"
- " .computeRawVarint32Size(dataSize);\n"
+ " .computeUInt32SizeNoTag(dataSize);\n"
"}");
} else {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index c22da8d7..99f52d40 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -61,10 +61,11 @@ bool EnumHasCustomOptions(const EnumDescriptor* descriptor) {
} // namespace
EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor,
- bool immutable_api,
- Context* context)
- : descriptor_(descriptor), immutable_api_(immutable_api),
- name_resolver_(context->GetNameResolver()) {
+ bool immutable_api, Context* context)
+ : descriptor_(descriptor),
+ immutable_api_(immutable_api),
+ context_(context),
+ name_resolver_(context->GetNameResolver()) {
for (int i = 0; i < descriptor_->value_count(); i++) {
const EnumValueDescriptor* value = descriptor_->value(i);
const EnumValueDescriptor* canonical_value =
@@ -85,10 +86,12 @@ EnumLiteGenerator::~EnumLiteGenerator() {}
void EnumLiteGenerator::Generate(io::Printer* printer) {
WriteEnumDocComment(printer, descriptor_);
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
printer->Print(
- "public enum $classname$\n"
- " implements com.google.protobuf.Internal.EnumLite {\n",
- "classname", descriptor_->name());
+ "public enum $classname$\n"
+ " implements com.google.protobuf.Internal.EnumLite {\n",
+ "classname", descriptor_->name());
+ printer->Annotate("classname", descriptor_);
printer->Indent();
for (int i = 0; i < canonical_values_.size(); i++) {
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h
index ee2f5f7a..f27cb76f 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.h
+++ b/src/google/protobuf/compiler/java/java_enum_lite.h
@@ -58,9 +58,8 @@ namespace java {
class EnumLiteGenerator {
public:
- explicit EnumLiteGenerator(const EnumDescriptor* descriptor,
- bool immutable_api,
- Context* context);
+ EnumLiteGenerator(const EnumDescriptor* descriptor, bool immutable_api,
+ Context* context);
~EnumLiteGenerator();
void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index c53aae6b..a06c5f6d 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -193,19 +193,19 @@ void MaybeRestartJavaMethod(io::Printer* printer,
} // namespace
-FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api,
- bool enforce_lite)
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options,
+ bool immutable_api)
: file_(file),
java_package_(FileJavaPackage(file, immutable_api)),
message_generators_(
new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
extension_generators_(
new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
- context_(new Context(file)),
+ context_(new Context(file, options)),
name_resolver_(context_->GetNameResolver()),
+ options_(options),
immutable_api_(immutable_api) {
classname_ = name_resolver_->GetFileClassName(file, immutable_api);
- context_->SetEnforceLite(enforce_lite);
generator_factory_.reset(
new ImmutableGeneratorFactory(context_.get()));
for (int i = 0; i < file_->message_type_count(); ++i) {
@@ -253,10 +253,13 @@ void FileGenerator::Generate(io::Printer* printer) {
"\n",
"package", java_package_);
}
+ PrintGeneratedAnnotation(
+ printer, '$', options_.annotate_code ? classname_ + ".java.pb.meta" : "");
printer->Print(
- "public final class $classname$ {\n"
- " private $classname$() {}\n",
- "classname", classname_);
+ "public final class $classname$ {\n"
+ " private $ctor$() {}\n",
+ "classname", classname_, "ctor", classname_);
+ printer->Annotate("classname", file_->name());
printer->Indent();
// -----------------------------------------------------------------
@@ -372,7 +375,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
"final", "");
printer->Indent();
- SharedCodeGenerator shared_code_generator(file_);
+ SharedCodeGenerator shared_code_generator(file_, options_);
shared_code_generator.GenerateDescriptors(printer);
int bytecode_estimate = 0;
@@ -523,20 +526,26 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer*
"}\n");
}
-template<typename GeneratorClass, typename DescriptorClass>
+template <typename GeneratorClass, typename DescriptorClass>
static void GenerateSibling(const string& package_dir,
const string& java_package,
const DescriptorClass* descriptor,
GeneratorContext* context,
- vector<string>* file_list,
+ vector<string>* file_list, bool annotate_code,
+ vector<string>* annotation_list,
const string& name_suffix,
GeneratorClass* generator,
void (GeneratorClass::*pfn)(io::Printer* printer)) {
string filename = package_dir + descriptor->name() + name_suffix + ".java";
file_list->push_back(filename);
+ string info_full_path = filename + ".pb.meta";
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
- io::Printer printer(output.get(), '$');
+ io::Printer printer(output.get(), '$',
+ annotate_code ? &annotation_collector : NULL);
printer.Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
@@ -551,55 +560,57 @@ static void GenerateSibling(const string& package_dir,
}
(generator->*pfn)(&printer);
+
+ if (annotate_code) {
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+ context->Open(info_full_path));
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ annotation_list->push_back(info_full_path);
+ }
}
void FileGenerator::GenerateSiblings(const string& package_dir,
GeneratorContext* context,
- vector<string>* file_list) {
+ vector<string>* file_list,
+ vector<string>* annotation_list) {
if (MultipleJavaFiles(file_, immutable_api_)) {
for (int i = 0; i < file_->enum_type_count(); i++) {
if (HasDescriptorMethods(file_, context_->EnforceLite())) {
EnumGenerator generator(file_->enum_type(i), immutable_api_,
context_.get());
- GenerateSibling<EnumGenerator>(package_dir, java_package_,
- file_->enum_type(i),
- context, file_list, "",
- &generator,
- &EnumGenerator::Generate);
+ GenerateSibling<EnumGenerator>(
+ package_dir, java_package_, file_->enum_type(i), context, file_list,
+ options_.annotate_code, annotation_list, "", &generator,
+ &EnumGenerator::Generate);
} else {
EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
context_.get());
- GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
- file_->enum_type(i),
- context, file_list, "",
- &generator,
- &EnumLiteGenerator::Generate);
+ GenerateSibling<EnumLiteGenerator>(
+ package_dir, java_package_, file_->enum_type(i), context, file_list,
+ options_.annotate_code, annotation_list, "", &generator,
+ &EnumLiteGenerator::Generate);
}
}
for (int i = 0; i < file_->message_type_count(); i++) {
if (immutable_api_) {
- GenerateSibling<MessageGenerator>(package_dir, java_package_,
- file_->message_type(i),
- context, file_list,
- "OrBuilder",
- message_generators_[i].get(),
- &MessageGenerator::GenerateInterface);
+ GenerateSibling<MessageGenerator>(
+ package_dir, java_package_, file_->message_type(i), context,
+ file_list, options_.annotate_code, annotation_list, "OrBuilder",
+ message_generators_[i].get(), &MessageGenerator::GenerateInterface);
}
- GenerateSibling<MessageGenerator>(package_dir, java_package_,
- file_->message_type(i),
- context, file_list, "",
- message_generators_[i].get(),
- &MessageGenerator::Generate);
+ GenerateSibling<MessageGenerator>(
+ package_dir, java_package_, file_->message_type(i), context,
+ file_list, options_.annotate_code, annotation_list, "",
+ message_generators_[i].get(), &MessageGenerator::Generate);
}
if (HasGenericServices(file_, context_->EnforceLite())) {
for (int i = 0; i < file_->service_count(); i++) {
google::protobuf::scoped_ptr<ServiceGenerator> generator(
generator_factory_->NewServiceGenerator(file_->service(i)));
- GenerateSibling<ServiceGenerator>(package_dir, java_package_,
- file_->service(i),
- context, file_list, "",
- generator.get(),
- &ServiceGenerator::Generate);
+ GenerateSibling<ServiceGenerator>(
+ package_dir, java_package_, file_->service(i), context, file_list,
+ options_.annotate_code, annotation_list, "", generator.get(),
+ &ServiceGenerator::Generate);
}
}
}
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 7dbeb94e..1e643f79 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -42,6 +42,7 @@
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
namespace google {
namespace protobuf {
@@ -67,8 +68,8 @@ namespace java {
class FileGenerator {
public:
- FileGenerator(const FileDescriptor* file, bool immutable_api = true,
- bool enforce_lite = false);
+ FileGenerator(const FileDescriptor* file, const Options& options,
+ bool immutable_api = true);
~FileGenerator();
// Checks for problems that would otherwise lead to cryptic compile errors.
@@ -83,12 +84,12 @@ class FileGenerator {
// service type).
void GenerateSiblings(const string& package_dir,
GeneratorContext* generator_context,
- vector<string>* file_list);
+ vector<string>* file_list,
+ vector<string>* annotation_list);
const string& java_package() { return java_package_; }
const string& classname() { return classname_; }
-
private:
void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer);
void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer);
@@ -105,9 +106,9 @@ class FileGenerator {
google::protobuf::scoped_ptr<GeneratorFactory> generator_factory_;
google::protobuf::scoped_ptr<Context> context_;
ClassNameResolver* name_resolver_;
+ const Options options_;
bool immutable_api_;
-
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index a46c7fc4..3c545e15 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -42,6 +42,7 @@
#include <google/protobuf/compiler/java/java_file.h>
#include <google/protobuf/compiler/java/java_generator_factory.h>
#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_options.h>
#include <google/protobuf/compiler/java/java_shared_code_generator.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
@@ -64,63 +65,60 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
// -----------------------------------------------------------------
// parse generator options
- // Name a file where we will write a list of generated file names, one
- // per line.
- string output_list_file;
-
vector<pair<string, string> > options;
ParseGeneratorParameter(parameter, &options);
+ Options file_options;
- bool generate_immutable_code = false;
- bool generate_mutable_code = false;
- bool generate_shared_code = false;
- bool enforce_lite = false;
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "output_list_file") {
- output_list_file = options[i].second;
+ file_options.output_list_file = options[i].second;
} else if (options[i].first == "immutable") {
- generate_immutable_code = true;
+ file_options.generate_immutable_code = true;
} else if (options[i].first == "mutable") {
- generate_mutable_code = true;
+ file_options.generate_mutable_code = true;
} else if (options[i].first == "shared") {
- generate_shared_code = true;
+ file_options.generate_shared_code = true;
} else if (options[i].first == "lite") {
- // When set, the protoc will generate the current files and all the
- // transitive dependencies as lite runtime.
- enforce_lite = true;
+ file_options.enforce_lite = true;
+ } else if (options[i].first == "annotate_code") {
+ file_options.annotate_code = true;
+ } else if (options[i].first == "annotation_list_file") {
+ file_options.annotation_list_file = options[i].second;
} else {
*error = "Unknown generator option: " + options[i].first;
return false;
}
}
- if (enforce_lite && generate_mutable_code) {
+ if (file_options.enforce_lite && file_options.generate_mutable_code) {
*error = "lite runtime generator option cannot be used with mutable API.";
return false;
}
// By default we generate immutable code and shared code for immutable API.
- if (!generate_immutable_code && !generate_mutable_code &&
- !generate_shared_code) {
- generate_immutable_code = true;
- generate_shared_code = true;
+ if (!file_options.generate_immutable_code &&
+ !file_options.generate_mutable_code &&
+ !file_options.generate_shared_code) {
+ file_options.generate_immutable_code = true;
+ file_options.generate_shared_code = true;
}
// -----------------------------------------------------------------
vector<string> all_files;
+ vector<string> all_annotations;
vector<FileGenerator*> file_generators;
- if (generate_immutable_code) {
- file_generators.push_back(
- new FileGenerator(file, /* immutable = */ true, enforce_lite));
+ if (file_options.generate_immutable_code) {
+ file_generators.push_back(new FileGenerator(file, file_options,
+ /* immutable = */ true));
}
- if (generate_mutable_code) {
- file_generators.push_back(
- new FileGenerator(file, /* mutable = */ false, enforce_lite));
+ if (file_options.generate_mutable_code) {
+ file_generators.push_back(new FileGenerator(file, file_options,
+ /* mutable = */ false));
}
for (int i = 0; i < file_generators.size(); ++i) {
if (!file_generators[i]->Validate(error)) {
@@ -140,15 +138,32 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
java_filename += file_generator->classname();
java_filename += ".java";
all_files.push_back(java_filename);
+ string info_full_path = java_filename + ".pb.meta";
+ if (file_options.annotate_code) {
+ all_annotations.push_back(info_full_path);
+ }
// Generate main java file.
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
context->Open(java_filename));
- io::Printer printer(output.get(), '$');
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ io::Printer printer(output.get(), '$', file_options.annotate_code
+ ? &annotation_collector
+ : NULL);
+
file_generator->Generate(&printer);
// Generate sibling files.
- file_generator->GenerateSiblings(package_dir, context, &all_files);
+ file_generator->GenerateSiblings(package_dir, context, &all_files,
+ &all_annotations);
+
+ if (file_options.annotate_code) {
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+ context->Open(info_full_path));
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ }
}
for (int i = 0; i < file_generators.size(); ++i) {
@@ -157,17 +172,29 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
file_generators.clear();
// Generate output list if requested.
- if (!output_list_file.empty()) {
+ if (!file_options.output_list_file.empty()) {
// Generate output list. This is just a simple text file placed in a
// deterministic location which lists the .java files being generated.
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
- context->Open(output_list_file));
+ context->Open(file_options.output_list_file));
io::Printer srclist_printer(srclist_raw_output.get(), '$');
for (int i = 0; i < all_files.size(); i++) {
srclist_printer.Print("$filename$\n", "filename", all_files[i]);
}
}
+ if (!file_options.annotation_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .java files being generated.
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> annotation_list_raw_output(
+ context->Open(file_options.annotation_list_file));
+ io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+ for (int i = 0; i < all_annotations.size(); i++) {
+ annotation_list_printer.Print("$filename$\n", "filename",
+ all_annotations[i]);
+ }
+ }
+
return true;
}
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index e24894b1..c31df265 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -101,6 +101,20 @@ string FieldName(const FieldDescriptor* field) {
} // namespace
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
+ const string& annotation_file) {
+ if (annotation_file.empty()) {
+ return;
+ }
+ string ptemplate =
+ "@javax.annotation.Generated(value=\"protoc\", comments=\"annotations:";
+ ptemplate.push_back(delimiter);
+ ptemplate.append("annotation_file");
+ ptemplate.push_back(delimiter);
+ ptemplate.append("\")\n");
+ printer->Print(ptemplate.c_str(), "annotation_file", annotation_file);
+}
+
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
string result;
// Note: I distrust ctype.h due to locales.
@@ -481,9 +495,9 @@ bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
return field->default_value_float() == 0.0;
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() == false;
-
- case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_ENUM:
+ return field->default_value_enum()->number() == 0;
+ case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
return false;
@@ -495,6 +509,11 @@ bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
return false;
}
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field) {
+ return GetJavaType(field) == JAVATYPE_BYTES &&
+ field->default_value_string() != "";
+}
+
const char* bit_masks[] = {
"0x00000001",
"0x00000002",
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index c850423e..5316d2f9 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -36,6 +36,8 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
#include <string>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
@@ -49,6 +51,17 @@ namespace java {
extern const char kThickSeparator[];
extern const char kThinSeparator[];
+// If annotation_file is non-empty, prints a javax.annotation.Generated
+// annotation to the given Printer. annotation_file will be referenced in the
+// annotation's comments field. delimiter should be the Printer's delimiter
+// character. annotation_file will be included verbatim into a Java literal
+// string, so it should not contain quotes or invalid Java escape sequences;
+// however, these are unlikely to appear in practice, as the value of
+// annotation_file should be generated from the filename of the source file
+// being annotated (which in turn must be a Java identifier plus ".java").
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter = '$',
+ const string& annotation_file = "");
+
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
// first letter.
string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
@@ -126,6 +139,38 @@ inline bool MultipleJavaFiles(
return descriptor->options().java_multiple_files();
}
+// Returns true if `descriptor` will be written to its own .java file.
+// `immutable` should be set to true if we're generating for the immutable API.
+template <typename Descriptor>
+bool IsOwnFile(const Descriptor* descriptor, bool immutable) {
+ return descriptor->containing_type() == NULL &&
+ MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+template <>
+inline bool IsOwnFile(const ServiceDescriptor* descriptor, bool immutable) {
+ return MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+// If `descriptor` describes an object with its own .java file,
+// returns the name (relative to that .java file) of the file that stores
+// annotation data for that descriptor. `suffix` is usually empty, but may
+// (e.g.) be "OrBuilder" for some generated interfaces.
+template <typename Descriptor>
+string AnnotationFileName(const Descriptor* descriptor, const string& suffix) {
+ return descriptor->name() + suffix + ".java.pb.meta";
+}
+
+template <typename Descriptor>
+void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer,
+ Descriptor* descriptor, bool immutable,
+ const string& suffix = "") {
+ if (context->options().annotate_code && IsOwnFile(descriptor, immutable)) {
+ PrintGeneratedAnnotation(printer, '$',
+ AnnotationFileName(descriptor, suffix));
+ }
+}
+
// Get the unqualified name that should be used for a field's field
// number constant.
string FieldConstantName(const FieldDescriptor *field);
@@ -169,11 +214,7 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field,
return DefaultValue(field, true, name_resolver);
}
bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
-
-// Does this message have specialized equals() and hashCode() methods?
-inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
- return descriptor->file()->options().java_generate_equals_and_hash();
-}
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field);
// Does this message class have descriptor and reflection methods?
inline bool HasDescriptorMethods(const Descriptor* descriptor,
@@ -344,6 +385,9 @@ inline bool CheckUtf8(const FieldDescriptor* descriptor) {
descriptor->file()->options().java_string_check_utf8();
}
+inline string GeneratedCodeVersionSuffix() {
+ return "V3";
+}
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
index 0de8cbe5..abf8e55c 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -93,7 +93,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
"\n");
@@ -193,11 +193,11 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" $name$_,\n"
" getParentForChildren(),\n"
@@ -535,7 +535,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
"\n");
@@ -763,11 +763,11 @@ GenerateBuilderMembers(io::Printer* printer) const {
" get$capitalized_name$BuilderList() {\n"
" return get$capitalized_name$FieldBuilder().getBuilderList();\n"
"}\n"
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" $name$_,\n"
" $get_mutable_bit_builder$,\n"
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
index 62f39302..dac1b51f 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -59,19 +59,28 @@ ImmutableLazyMessageFieldLiteGenerator::
void ImmutableLazyMessageFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "private com.google.protobuf.LazyFieldLite $name$_ =\n"
- " new com.google.protobuf.LazyFieldLite();\n");
+ "private com.google.protobuf.LazyFieldLite $name$_;");
PrintExtraFieldInfo(variables_, printer);
WriteFieldDocComment(printer, descriptor_);
- printer->Print(variables_,
- "$deprecation$public boolean has$capitalized_name$() {\n"
- " return $get_has_field_bit_message$;\n"
- "}\n");
+ if (SupportFieldPresence(descriptor_->file())) {
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $get_has_field_bit_message$;\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "$deprecation$public boolean has$capitalized_name$() {\n"
+ " return $name$_ != null;\n"
+ "}\n");
+ }
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"$deprecation$public $type$ get$capitalized_name$() {\n"
+ " if ($name$_ == null) {\n"
+ " return $type$.getDefaultInstance();\n"
+ " }\n"
" return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
"}\n");
@@ -82,8 +91,11 @@ GenerateMembers(io::Printer* printer) const {
" if (value == null) {\n"
" throw new NullPointerException();\n"
" }\n"
+ " if ($name$_ == null) {\n"
+ " $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+ " }\n"
" $name$_.setValue(value);\n"
- " $set_has_field_bit_message$;\n"
+ " $set_has_field_bit_message$\n"
"}\n");
// Field.Builder setField(Field.Builder builderForValue)
@@ -91,30 +103,36 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(variables_,
"private void set$capitalized_name$(\n"
" $type$.Builder builderForValue) {\n"
+ " if ($name$_ == null) {\n"
+ " $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+ " }\n"
" $name$_.setValue(builderForValue.build());\n"
- " $set_has_field_bit_message$;\n"
+ " $set_has_field_bit_message$\n"
"}\n");
// Field.Builder mergeField(Field value)
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"private void merge$capitalized_name$($type$ value) {\n"
- " if ($get_has_field_bit_message$ &&\n"
+ " if (has$capitalized_name$() &&\n"
" !$name$_.containsDefaultInstance()) {\n"
" $name$_.setValue(\n"
" $type$.newBuilder(\n"
" get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
" } else {\n"
+ " if ($name$_ == null) {\n"
+ " $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+ " }\n"
" $name$_.setValue(value);\n"
+ " $set_has_field_bit_message$\n"
" }\n"
- " $set_has_field_bit_message$;\n"
"}\n");
// Field.Builder clearField()
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
"private void clear$capitalized_name$() {\n"
- " $name$_.clear();\n"
+ " $name$_ = null;\n"
" $clear_has_field_bit_message$;\n"
"}\n");
}
@@ -177,31 +195,30 @@ GenerateBuilderMembers(io::Printer* printer) const {
void ImmutableLazyMessageFieldLiteGenerator::
-GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.clear();\n");
-}
+GenerateInitializationCode(io::Printer* printer) const {}
void ImmutableLazyMessageFieldLiteGenerator::
GenerateVisitCode(io::Printer* printer) const {
printer->Print(variables_,
- "$name$_ = visitor.visitLazyMessage(\n"
- " has$capitalized_name$(), $name$_,\n"
- " other.has$capitalized_name$(), other.$name$_);\n");
+ "$name$_ = visitor.visitLazyMessage($name$_, other.$name$_);\n");
}
void ImmutableLazyMessageFieldLiteGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
+ "if ($name$_ == null) {\n"
+ " $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+ "}\n"
"$name$_.mergeFrom(input, extensionRegistry);\n");
printer->Print(variables_,
- "$set_has_field_bit_message$;\n");
+ "$set_has_field_bit_message$\n");
}
void ImmutableLazyMessageFieldLiteGenerator::
GenerateSerializationCode(io::Printer* printer) const {
// Do not de-serialize lazy fields.
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if (has$capitalized_name$()) {\n"
" output.writeBytes($number$, $name$_.toByteString());\n"
"}\n");
}
@@ -209,7 +226,7 @@ GenerateSerializationCode(io::Printer* printer) const {
void ImmutableLazyMessageFieldLiteGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "if ($get_has_field_bit_message$) {\n"
+ "if (has$capitalized_name$()) {\n"
" size += com.google.protobuf.CodedOutputStream\n"
" .computeLazyFieldSize($number$, $name$_);\n"
"}\n");
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 2a551ca4..16c5bec5 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -88,11 +88,18 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
name_resolver->GetImmutableClassName(descriptor->message_type());
const FieldDescriptor* key = KeyField(descriptor);
const FieldDescriptor* value = ValueField(descriptor);
+ const JavaType keyJavaType = GetJavaType(key);
+ const JavaType valueJavaType = GetJavaType(value);
+
(*variables)["key_type"] = TypeName(key, name_resolver, false);
(*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
(*variables)["key_wire_type"] = WireType(key);
(*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
- if (GetJavaType(value) == JAVATYPE_ENUM) {
+ (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ?
+ "if (key == null) { throw new java.lang.NullPointerException(); }" : "";
+ (*variables)["value_null_check"] = IsReferenceType(valueJavaType) ?
+ "if (value == null) { throw new java.lang.NullPointerException(); }" : "";
+ if (valueJavaType == JAVATYPE_ENUM) {
// We store enums as Integers internally.
(*variables)["value_type"] = "int";
(*variables)["boxed_value_type"] = "java.lang.Integer";
@@ -135,7 +142,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["default_entry"] = (*variables)["capitalized_name"] +
"DefaultEntryHolder.defaultEntry";
- (*variables)["lite"] = "";
(*variables)["map_field_parameter"] = (*variables)["default_entry"];
(*variables)["descriptor"] =
name_resolver->GetImmutableClassName(descriptor->file()) +
@@ -169,25 +175,95 @@ int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
void ImmutableMapFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$boolean contains$capitalized_name$(\n"
+ " $key_type$ key);\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "get$capitalized_name$();\n");
+ "get$capitalized_name$Map();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$$value_enum_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$$value_enum_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key);\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$Value();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
- "get$capitalized_name$Value();\n");
+ "get$capitalized_name$ValueMap();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$ValueOrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$ValueOrThrow(\n"
+ " $key_type$ key);\n");
}
} else {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
- "get$capitalized_name$();\n");
+ "get$capitalized_name$Map();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key);\n");
}
}
@@ -196,9 +272,9 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private static final class $capitalized_name$DefaultEntryHolder {\n"
- " static final com.google.protobuf.MapEntry$lite$<\n"
+ " static final com.google.protobuf.MapEntry<\n"
" $type_parameters$> defaultEntry =\n"
- " com.google.protobuf.MapEntry$lite$\n"
+ " com.google.protobuf.MapEntry\n"
" .<$type_parameters$>newDefaultInstance(\n"
" $descriptor$\n"
" $key_wire_type$,\n"
@@ -208,12 +284,12 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
printer->Print(
variables_,
- "private com.google.protobuf.MapField$lite$<\n"
+ "private com.google.protobuf.MapField<\n"
" $type_parameters$> $name$_;\n"
- "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "private com.google.protobuf.MapField<$type_parameters$>\n"
"internalGet$capitalized_name$() {\n"
" if ($name$_ == null) {\n"
- " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " return com.google.protobuf.MapField.emptyMapField(\n"
" $map_field_parameter$);\n"
" }\n"
" return $name$_;\n"
@@ -227,57 +303,29 @@ GenerateMembers(io::Printer* printer) const {
" com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
" $value_enum_type$.internalGetValueMap(),\n"
" $unrecognized_value$);\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(
- variables_,
- "$deprecation$\n"
- "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "get$capitalized_name$Value() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
- "}\n");
- }
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(
- variables_,
- "$deprecation$\n"
- "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "get$capitalized_name$() {\n"
- " return new com.google.protobuf.Internal.MapAdapter<\n"
- " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " internalGet$capitalized_name$().getMap(),\n"
- " $name$ValueConverter);\n"
- "}\n");
- } else {
- WriteFieldDocComment(printer, descriptor_);
- printer->Print(
- variables_,
- "$deprecation$\n"
- "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
- "}\n");
}
+ GenerateMapGetters(printer);
}
void ImmutableMapFieldGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(
variables_,
- "private com.google.protobuf.MapField$lite$<\n"
+ "private com.google.protobuf.MapField<\n"
" $type_parameters$> $name$_;\n"
- "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "private com.google.protobuf.MapField<$type_parameters$>\n"
"internalGet$capitalized_name$() {\n"
" if ($name$_ == null) {\n"
- " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+ " return com.google.protobuf.MapField.emptyMapField(\n"
" $map_field_parameter$);\n"
" }\n"
" return $name$_;\n"
"}\n"
- "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "private com.google.protobuf.MapField<$type_parameters$>\n"
"internalGetMutable$capitalized_name$() {\n"
" $on_changed$;\n"
" if ($name$_ == null) {\n"
- " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+ " $name$_ = com.google.protobuf.MapField.newMapField(\n"
" $map_field_parameter$);\n"
" }\n"
" if (!$name$_.isMutable()) {\n"
@@ -285,53 +333,82 @@ GenerateBuilderMembers(io::Printer* printer) const {
" }\n"
" return $name$_;\n"
"}\n");
+ GenerateMapGetters(printer);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " getMutable$capitalized_name$().clear();\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public Builder remove$capitalized_name$(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " getMutable$capitalized_name$().remove(key);\n"
+ " return this;\n"
+ "}\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
+ "/**\n"
+ " * Use alternate mutation accessors instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "get$capitalized_name$() {\n"
+ "getMutable$capitalized_name$() {\n"
" return new com.google.protobuf.Internal.MapAdapter<\n"
" $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " internalGet$capitalized_name$().getMap(),\n"
+ " internalGetMutable$capitalized_name$().getMutableMap(),\n"
" $name$ValueConverter);\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
- "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "getMutable$capitalized_name$() {\n"
- " return new com.google.protobuf.Internal.MapAdapter<\n"
- " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " internalGetMutable$capitalized_name$().getMutableMap(),\n"
- " $name$ValueConverter);\n"
+ "$deprecation$public Builder put$capitalized_name$(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ value) {\n"
+ " $key_null_check$\n"
+ " $value_null_check$\n"
+ " getMutable$capitalized_name$().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
+ // TODO(arielb): null check map keys/values here and everywhere else
+ // related to putAll
"$deprecation$public Builder putAll$capitalized_name$(\n"
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
" getMutable$capitalized_name$().putAll(values);\n"
" return this;\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
+ "/**\n"
+ " * Use alternate mutation accessors instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "get$capitalized_name$Value() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
+ "getMutable$capitalized_name$Value() {\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
- "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "getMutable$capitalized_name$Value() {\n"
- " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "$deprecation$public Builder put$capitalized_name$Value(\n"
+ " $key_type$ key,\n"
+ " $value_type$ value) {\n"
+ " $key_null_check$\n"
+ " if ($value_enum_type$.forNumber(value) == null) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " getMutable$capitalized_name$Value().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
@@ -343,23 +420,33 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
}
} else {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
+ "/**\n"
+ " * Use alternate mutation accessors instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$type_parameters$>\n"
+ "getMutable$capitalized_name$() {\n"
+ " return internalGetMutable$capitalized_name$().getMutableMap();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "public java.util.Map<$type_parameters$>\n"
- "getMutable$capitalized_name$() {\n"
- " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "$deprecation$"
+ "public Builder put$capitalized_name$(\n"
+ " $key_type$ key,\n"
+ " $value_type$ value) {\n"
+ " $key_null_check$\n"
+ " $value_null_check$\n"
+ " getMutable$capitalized_name$().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$public Builder putAll$capitalized_name$(\n"
+ "$deprecation$\n"
+ "public Builder putAll$capitalized_name$(\n"
" java.util.Map<$type_parameters$> values) {\n"
" getMutable$capitalized_name$().putAll(values);\n"
" return this;\n"
@@ -368,6 +455,165 @@ GenerateBuilderMembers(io::Printer* printer) const {
}
void ImmutableMapFieldGenerator::
+GenerateMapGetters(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return internalGet$capitalized_name$().getMap().size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public boolean contains$capitalized_name$(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " return internalGet$capitalized_name$().getMap().containsKey(key);\n"
+ "}\n");
+ if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$() {\n"
+ " return get$capitalized_name$Map();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$Map() {\n"
+ " return new com.google.protobuf.Internal.MapAdapter<\n"
+ " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+ " internalGet$capitalized_name$().getMap(),\n"
+ " $name$ValueConverter);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " return map.containsKey(key)\n"
+ " ? $name$ValueConverter.doForward(map.get(key))\n"
+ " : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return $name$ValueConverter.doForward(map.get(key));\n"
+ "}\n");
+ if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "get$capitalized_name$Value() {\n"
+ " return get$capitalized_name$ValueMap();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "get$capitalized_name$ValueMap() {\n"
+ " return internalGet$capitalized_name$().getMap();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
+ "}\n");
+ }
+ } else {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return get$capitalized_name$Map();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+ " return internalGet$capitalized_name$().getMap();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " internalGet$capitalized_name$().getMap();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
+ "}\n");
+ }
+}
+
+void ImmutableMapFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// Nothing to initialize.
}
@@ -405,7 +651,7 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(
variables_,
"if (!$get_mutable_bit_parser$) {\n"
- " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+ " $name$_ = com.google.protobuf.MapField.newMapField(\n"
" $map_field_parameter$);\n"
" $set_mutable_bit_parser$;\n"
"}\n");
@@ -414,7 +660,7 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(
variables_,
"com.google.protobuf.ByteString bytes = input.readBytes();\n"
- "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ "com.google.protobuf.MapEntry<$type_parameters$>\n"
"$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
printer->Print(
variables_,
@@ -426,7 +672,7 @@ GenerateParsingCode(io::Printer* printer) const {
} else {
printer->Print(
variables_,
- "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ "com.google.protobuf.MapEntry<$type_parameters$>\n"
"$name$ = input.readMessage(\n"
" $default_entry$.getParserForType(), extensionRegistry);\n"
"$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
@@ -444,7 +690,7 @@ GenerateSerializationCode(io::Printer* printer) const {
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
" : internalGet$capitalized_name$().getMap().entrySet()) {\n"
- " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ " com.google.protobuf.MapEntry<$type_parameters$>\n"
" $name$ = $default_entry$.newBuilderForType()\n"
" .setKey(entry.getKey())\n"
" .setValue(entry.getValue())\n"
@@ -459,7 +705,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
" : internalGet$capitalized_name$().getMap().entrySet()) {\n"
- " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+ " com.google.protobuf.MapEntry<$type_parameters$>\n"
" $name$ = $default_entry$.newBuilderForType()\n"
" .setKey(entry.getKey())\n"
" .setValue(entry.getValue())\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index f2768f3a..ae7ce7c5 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -69,6 +69,7 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
const FieldDescriptor* descriptor_;
map<string, string> variables_;
ClassNameResolver* name_resolver_;
+ void GenerateMapGetters(io::Printer* printer) const;
};
} // namespace java
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index b80d4139..0d3bea17 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -88,10 +88,18 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
name_resolver->GetImmutableClassName(descriptor->message_type());
const FieldDescriptor* key = KeyField(descriptor);
const FieldDescriptor* value = ValueField(descriptor);
+ const JavaType keyJavaType = GetJavaType(key);
+ const JavaType valueJavaType = GetJavaType(value);
+
(*variables)["key_type"] = TypeName(key, name_resolver, false);
(*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
(*variables)["key_wire_type"] = WireType(key);
(*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+ (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ?
+ "if (key == null) { throw new java.lang.NullPointerException(); }" : "";
+ (*variables)["value_null_check"] = IsReferenceType(valueJavaType) ?
+ "if (value == null) { throw new java.lang.NullPointerException(); }" : "";
+
if (GetJavaType(value) == JAVATYPE_ENUM) {
// We store enums as Integers internally.
(*variables)["value_type"] = "int";
@@ -127,8 +135,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["default_entry"] = (*variables)["capitalized_name"] +
"DefaultEntryHolder.defaultEntry";
- (*variables)["lite"] = "Lite";
- (*variables)["descriptor"] = "";
}
} // namespace
@@ -157,25 +163,95 @@ int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const {
void ImmutableMapFieldLiteGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$int get$capitalized_name$Count();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$boolean contains$capitalized_name$(\n"
+ " $key_type$ key);\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "get$capitalized_name$();\n");
+ "get$capitalized_name$Map();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$$value_enum_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$$value_enum_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key);\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$Value();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
- "get$capitalized_name$Value();\n");
+ "get$capitalized_name$ValueMap();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$ValueOrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$ValueOrThrow(\n"
+ " $key_type$ key);\n");
}
} else {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "java.util.Map<$type_parameters$>\n"
+ "get$capitalized_name$();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$java.util.Map<$type_parameters$>\n"
- "get$capitalized_name$();\n");
+ "get$capitalized_name$Map();\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue);\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "$value_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key);\n");
}
}
@@ -184,11 +260,10 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private static final class $capitalized_name$DefaultEntryHolder {\n"
- " static final com.google.protobuf.MapEntry$lite$<\n"
+ " static final com.google.protobuf.MapEntryLite<\n"
" $type_parameters$> defaultEntry =\n"
- " com.google.protobuf.MapEntry$lite$\n"
+ " com.google.protobuf.MapEntryLite\n"
" .<$type_parameters$>newDefaultInstance(\n"
- " $descriptor$\n"
" $key_wire_type$,\n"
" $key_default_value$,\n"
" $value_wire_type$,\n"
@@ -196,20 +271,35 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
printer->Print(
variables_,
- "private com.google.protobuf.MapField$lite$<\n"
+ "private com.google.protobuf.MapFieldLite<\n"
" $type_parameters$> $name$_ =\n"
- " com.google.protobuf.MapField$lite$.emptyMapField();\n"
- "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ " com.google.protobuf.MapFieldLite.emptyMapField();\n"
+ "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
"internalGet$capitalized_name$() {\n"
" return $name$_;\n"
"}\n"
- "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+ "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
"internalGetMutable$capitalized_name$() {\n"
" if (!$name$_.isMutable()) {\n"
- " $name$_ = $name$_.copy();\n"
+ " $name$_ = $name$_.mutableCopy();\n"
" }\n"
" return $name$_;\n"
"}\n");
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return internalGet$capitalized_name$().size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public boolean contains$capitalized_name$(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " return internalGet$capitalized_name$().containsKey(key);\n"
+ "}\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
printer->Print(
variables_,
@@ -219,34 +309,146 @@ GenerateMembers(io::Printer* printer) const {
" com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
" $value_enum_type$.internalGetValueMap(),\n"
" $unrecognized_value$);\n");
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$() {\n"
+ " return get$capitalized_name$Map();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+ "get$capitalized_name$Map() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " new com.google.protobuf.Internal.MapAdapter<\n"
+ " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+ " internalGet$capitalized_name$(),\n"
+ " $name$ValueConverter));\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " return map.containsKey(key)\n"
+ " ? $name$ValueConverter.doForward(map.get(key))\n"
+ " : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return $name$ValueConverter.doForward(map.get(key));\n"
+ "}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+ "get$capitalized_name$Value() {\n"
+ " return get$capitalized_name$ValueMap();\n"
+ "}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "get$capitalized_name$Value() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
+ "get$capitalized_name$ValueMap() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " internalGet$capitalized_name$());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
"}\n");
}
+ } else {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+ " return get$capitalized_name$Map();\n"
+ "}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$\n"
- "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "get$capitalized_name$() {\n"
- " return new com.google.protobuf.Internal.MapAdapter<\n"
- " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " internalGet$capitalized_name$().getMap(),\n"
- " $name$ValueConverter);\n"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " internalGet$capitalized_name$());\n"
"}\n");
- } else {
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$\n"
- "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return internalGet$capitalized_name$().getMap();\n"
+ "public $value_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " internalGet$capitalized_name$();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
"}\n");
}
@@ -256,10 +458,10 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "getMutable$capitalized_name$() {\n"
+ "getMutable$capitalized_name$Map() {\n"
" return new com.google.protobuf.Internal.MapAdapter<\n"
" $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
- " internalGetMutable$capitalized_name$().getMutableMap(),\n"
+ " internalGetMutable$capitalized_name$(),\n"
" $name$ValueConverter);\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
@@ -267,8 +469,8 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "getMutable$capitalized_name$Value() {\n"
- " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "getMutable$capitalized_name$ValueMap() {\n"
+ " return internalGetMutable$capitalized_name$();\n"
"}\n");
}
} else {
@@ -276,88 +478,252 @@ GenerateMembers(io::Printer* printer) const {
printer->Print(
variables_,
"private java.util.Map<$type_parameters$>\n"
- "getMutable$capitalized_name$() {\n"
- " return internalGetMutable$capitalized_name$().getMutableMap();\n"
+ "getMutable$capitalized_name$Map() {\n"
+ " return internalGetMutable$capitalized_name$();\n"
"}\n");
}
}
void ImmutableMapFieldLiteGenerator::
GenerateBuilderMembers(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public int get$capitalized_name$Count() {\n"
+ " return instance.get$capitalized_name$Map().size();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public boolean contains$capitalized_name$(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " return instance.get$capitalized_name$Map().containsKey(key);\n"
+ "}\n");
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public Builder clear$capitalized_name$() {\n"
+ " copyOnWrite();\n"
+ " instance.getMutable$capitalized_name$Map().clear();\n"
+ " return this;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public Builder remove$capitalized_name$(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " copyOnWrite();\n"
+ " instance.getMutable$capitalized_name$Map().remove(key);\n"
+ " return this;\n"
+ "}\n");
if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
"get$capitalized_name$() {\n"
- " return instance.get$capitalized_name$();\n"
+ " return get$capitalized_name$Map();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
- "getMutable$capitalized_name$() {\n"
+ "get$capitalized_name$Map() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " instance.get$capitalized_name$Map());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+ " instance.get$capitalized_name$Map();\n"
+ " return map.containsKey(key)\n"
+ " ? map.get(key)\n"
+ " : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+ " instance.get$capitalized_name$Map();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$public Builder put$capitalized_name$(\n"
+ " $key_type$ key,\n"
+ " $value_enum_type$ value) {\n"
+ " $key_null_check$\n"
+ " $value_null_check$\n"
" copyOnWrite();\n"
- " return instance.getMutable$capitalized_name$();\n"
+ " instance.getMutable$capitalized_name$Map().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$public Builder putAll$capitalized_name$(\n"
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
- " getMutable$capitalized_name$().putAll(values);\n"
+ " copyOnWrite();\n"
+ " instance.getMutable$capitalized_name$Map().putAll(values);\n"
" return this;\n"
"}\n");
if (SupportUnknownEnumValue(descriptor_->file())) {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "$deprecation$\n"
+ "/**\n"
+ " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
"get$capitalized_name$Value() {\n"
- " return instance.get$capitalized_name$Value();\n"
+ " return get$capitalized_name$ValueMap();\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$\n"
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
- "getMutable$capitalized_name$Value() {\n"
+ "get$capitalized_name$ValueMap() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " instance.get$capitalized_name$ValueMap());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " instance.get$capitalized_name$ValueMap();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+ " instance.get$capitalized_name$ValueMap();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$public Builder put$capitalized_name$Value(\n"
+ " $key_type$ key,\n"
+ " $value_type$ value) {\n"
+ " $key_null_check$\n"
+ " if ($value_enum_type$.forNumber(value) == null) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
" copyOnWrite();\n"
- " return instance.getMutable$capitalized_name$Value();\n"
+ " instance.getMutable$capitalized_name$ValueMap().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
"$deprecation$public Builder putAll$capitalized_name$Value(\n"
" java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
- " getMutable$capitalized_name$Value().putAll(values);\n"
+ " copyOnWrite();\n"
+ " instance.getMutable$capitalized_name$ValueMap().putAll(values);\n"
" return this;\n"
"}\n");
}
} else {
- WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
+ "/**\n"
+ " * Use {@link #get$capitalized_name$Map()} instead.\n"
+ " */\n"
+ "@java.lang.Deprecated\n"
"public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
- " return instance.get$capitalized_name$();\n"
+ " return get$capitalized_name$Map();\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$"
+ "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+ " return java.util.Collections.unmodifiableMap(\n"
+ " instance.get$capitalized_name$Map());\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$OrDefault(\n"
+ " $key_type$ key,\n"
+ " $value_type$ defaultValue) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " instance.get$capitalized_name$Map();\n"
+ " return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+ "}\n");
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$deprecation$\n"
+ "public $value_type$ get$capitalized_name$OrThrow(\n"
+ " $key_type$ key) {\n"
+ " $key_null_check$\n"
+ " java.util.Map<$type_parameters$> map =\n"
+ " instance.get$capitalized_name$Map();\n"
+ " if (!map.containsKey(key)) {\n"
+ " throw new java.lang.IllegalArgumentException();\n"
+ " }\n"
+ " return map.get(key);\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
- "public java.util.Map<$type_parameters$>\n"
- "getMutable$capitalized_name$() {\n"
+ "$deprecation$"
+ "public Builder put$capitalized_name$(\n"
+ " $key_type$ key,\n"
+ " $value_type$ value) {\n"
+ " $key_null_check$\n"
+ " $value_null_check$\n"
" copyOnWrite();\n"
- " return instance.getMutable$capitalized_name$();\n"
+ " instance.getMutable$capitalized_name$Map().put(key, value);\n"
+ " return this;\n"
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
+ "$deprecation$"
"public Builder putAll$capitalized_name$(\n"
" java.util.Map<$type_parameters$> values) {\n"
- " getMutable$capitalized_name$().putAll(values);\n"
+ " copyOnWrite();\n"
+ " instance.getMutable$capitalized_name$Map().putAll(values);\n"
" return this;\n"
"}\n");
}
@@ -377,8 +743,8 @@ void ImmutableMapFieldLiteGenerator::
GenerateVisitCode(io::Printer* printer) const {
printer->Print(
variables_,
- "$name$_ = visitor.visitMap(internalGetMutable$capitalized_name$(),\n"
- " other.internalGet$capitalized_name$());\n");
+ "$name$_ = visitor.visitMap(\n"
+ " $name$_, other.internalGet$capitalized_name$());\n");
}
void ImmutableMapFieldLiteGenerator::
@@ -392,29 +758,26 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(
variables_,
"if (!$name$_.isMutable()) {\n"
- " $name$_ = $name$_.copy();\n"
+ " $name$_ = $name$_.mutableCopy();\n"
"}\n");
if (!SupportUnknownEnumValue(descriptor_->file()) &&
GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
printer->Print(
variables_,
"com.google.protobuf.ByteString bytes = input.readBytes();\n"
- "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+ "java.util.Map.Entry<$type_parameters$> $name$ =\n"
+ " $default_entry$.parseEntry(bytes, extensionRegistry);\n");
printer->Print(
variables_,
"if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
" super.mergeLengthDelimitedField($number$, bytes);\n"
"} else {\n"
- " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+ " $name$_.put($name$);\n"
"}\n");
} else {
printer->Print(
variables_,
- "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- "$name$ = input.readMessage(\n"
- " $default_entry$.getParserForType(), extensionRegistry);\n"
- "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+ "$default_entry$.parseInto($name$_, input, extensionRegistry);");
}
}
@@ -428,13 +791,9 @@ GenerateSerializationCode(io::Printer* printer) const {
printer->Print(
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
- " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
- " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- " $name$ = $default_entry$.newBuilderForType()\n"
- " .setKey(entry.getKey())\n"
- " .setValue(entry.getValue())\n"
- " .build();\n"
- " output.writeMessage($number$, $name$);\n"
+ " : internalGet$capitalized_name$().entrySet()) {\n"
+ " $default_entry$.serializeTo(\n"
+ " output, $number$, entry.getKey(), entry.getValue());\n"
"}\n");
}
@@ -443,14 +802,9 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(
variables_,
"for (java.util.Map.Entry<$type_parameters$> entry\n"
- " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
- " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
- " $name$ = $default_entry$.newBuilderForType()\n"
- " .setKey(entry.getKey())\n"
- " .setValue(entry.getValue())\n"
- " .build();\n"
- " size += com.google.protobuf.CodedOutputStream\n"
- " .computeMessageSize($number$, $name$);\n"
+ " : internalGet$capitalized_name$().entrySet()) {\n"
+ " size += $default_entry$.computeMessageSize(\n"
+ " $number$, entry.getKey(), entry.getValue());\n"
"}\n");
}
@@ -466,7 +820,7 @@ void ImmutableMapFieldLiteGenerator::
GenerateHashCode(io::Printer* printer) const {
printer->Print(
variables_,
- "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+ "if (!internalGet$capitalized_name$().isEmpty()) {\n"
" hash = (37 * hash) + $constant_name$;\n"
" hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
"}\n");
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 4c474a48..d55a9849 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -248,22 +248,27 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) {
// ===================================================================
void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+ /* immutable = */ true, "OrBuilder");
if (descriptor_->extension_range_count() > 0) {
printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.GeneratedMessage.\n"
- " ExtendableMessageOrBuilder<$classname$> {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
+ "public interface $classname$OrBuilder$idend$ extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.GeneratedMessage.\n"
+ " ExtendableMessageOrBuilder<$classname$> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name(),
+ "idend", "");
} else {
printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.MessageOrBuilder {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
+ "public interface $classname$OrBuilder$idend$ extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name(),
+ "idend", "");
}
+ printer->Annotate("classname", "idend", descriptor_);
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -291,9 +296,7 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
// ===================================================================
void ImmutableMessageGenerator::Generate(io::Printer* printer) {
- bool is_own_file =
- descriptor_->containing_type() == NULL &&
- MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+ bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
map<string, string> variables;
variables["static"] = is_own_file ? " " : " static ";
@@ -301,22 +304,29 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
WriteMessageDocComment(printer, descriptor_);
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+ /* immutable = */ true);
// The builder_type stores the super type name of the nested Builder class.
string builder_type;
if (descriptor_->extension_range_count() > 0) {
printer->Print(variables,
- "public $static$final class $classname$ extends\n"
- " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
- " $classname$> implements\n"
- " $extra_interfaces$\n"
- " $classname$OrBuilder {\n");
+ "public $static$final class $classname$ extends\n");
+ printer->Annotate("classname", descriptor_);
+ printer->Print(
+ variables,
+ " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+ " $classname$> implements\n"
+ " $extra_interfaces$\n"
+ " $classname$OrBuilder {\n");
builder_type = strings::Substitute(
"com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
name_resolver_->GetImmutableClassName(descriptor_));
} else {
printer->Print(variables,
- "public $static$final class $classname$ extends\n"
+ "public $static$final class $classname$ extends\n");
+ printer->Annotate("classname", descriptor_);
+ printer->Print(variables,
" com.google.protobuf.GeneratedMessage implements\n"
" $extra_interfaces$\n"
" $classname$OrBuilder {\n");
@@ -485,9 +495,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
if (context_->HasGeneratedMethods(descriptor_)) {
GenerateIsInitialized(printer);
GenerateMessageSerializationMethods(printer);
- }
-
- if (HasEqualsAndHashCode(descriptor_)) {
GenerateEqualsAndHashCode(printer);
}
@@ -1225,8 +1232,7 @@ GenerateParsingConstructor(io::Printer* printer) {
"default: {\n"
" if (!input.skipField(tag)) {\n"
" done = true;\n" // it's an endgroup tag
- " }\n");
- printer->Print(
+ " }\n"
" break;\n"
"}\n");
}
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index e9fc57c2..da1447c1 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -92,8 +92,7 @@ class MessageGenerator {
class ImmutableMessageGenerator : public MessageGenerator {
public:
- explicit ImmutableMessageGenerator(const Descriptor* descriptor,
- Context* context);
+ ImmutableMessageGenerator(const Descriptor* descriptor, Context* context);
virtual ~ImmutableMessageGenerator();
virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 455516f6..cc627b5a 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -71,6 +71,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["deprecation"] = descriptor->options().deprecated()
? "@java.lang.Deprecated " : "";
(*variables)["on_changed"] = "onChanged();";
+ (*variables)["ver"] = GeneratedCodeVersionSuffix();
+ (*variables)["get_parser"] =
+ ExposePublicParser(descriptor->message_type()->file())
+ ? "PARSER" : "parser()";
if (SupportFieldPresence(descriptor->file())) {
// For singular messages and builders, one bit is used for the hasField bit.
@@ -252,7 +256,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
"\n");
@@ -374,11 +378,11 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" get$capitalized_name$(),\n"
" getParentForChildren(),\n"
@@ -451,11 +455,11 @@ GenerateParsingCode(io::Printer* printer) const {
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "$name$_ = input.readGroup($number$, $type$.parser(),\n"
+ "$name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
" extensionRegistry);\n");
} else {
printer->Print(variables_,
- "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n");
+ "$name$_ = input.readMessage($type$.$get_parser$, extensionRegistry);\n");
}
printer->Print(variables_,
@@ -560,7 +564,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
"\n");
@@ -683,14 +687,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
"}\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "private com.google.protobuf.SingleFieldBuilder<\n"
+ "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
" if (!($has_oneof_case_message$)) {\n"
" $oneof_name$_ = $type$.getDefaultInstance();\n"
" }\n"
- " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+ " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" ($type$) $oneof_name$_,\n"
" getParentForChildren(),\n"
@@ -735,12 +739,12 @@ GenerateParsingCode(io::Printer* printer) const {
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n"
+ "$oneof_name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
" extensionRegistry);\n");
} else {
printer->Print(variables_,
"$oneof_name$_ =\n"
- " input.readMessage($type$.parser(), extensionRegistry);\n");
+ " input.readMessage($type$.$get_parser$, extensionRegistry);\n");
}
printer->Print(variables_,
@@ -920,7 +924,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
printer->Print(variables_,
// If this builder is non-null, it is used and the other fields are
// ignored.
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
"\n");
@@ -1137,11 +1141,11 @@ GenerateBuilderMembers(io::Printer* printer) const {
" get$capitalized_name$BuilderList() {\n"
" return get$capitalized_name$FieldBuilder().getBuilderList();\n"
"}\n"
- "private com.google.protobuf.RepeatedFieldBuilder<\n"
+ "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder> \n"
" get$capitalized_name$FieldBuilder() {\n"
" if ($name$Builder_ == null) {\n"
- " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+ " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" $name$_,\n"
" $get_mutable_bit_builder$,\n"
@@ -1232,11 +1236,12 @@ GenerateParsingCode(io::Printer* printer) const {
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
printer->Print(variables_,
- "$name$_.add(input.readGroup($number$, $type$.parser(),\n"
+ "$name$_.add(input.readGroup($number$, $type$.$get_parser$,\n"
" extensionRegistry));\n");
} else {
printer->Print(variables_,
- "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n");
+ "$name$_.add(\n"
+ " input.readMessage($type$.$get_parser$, extensionRegistry));\n");
}
}
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index d4d2593a..7c8c4a03 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -120,23 +120,28 @@ int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers(
// ===================================================================
void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+ /* immutable = */ true, "OrBuilder");
if (descriptor_->extension_range_count() > 0) {
printer->Print(
- "public interface $classname$OrBuilder extends \n"
- " $extra_interfaces$\n"
- " com.google.protobuf.GeneratedMessageLite.\n"
- " ExtendableMessageOrBuilder<\n"
- " $classname$, $classname$.Builder> {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
+ "public interface $classname$OrBuilder$idend$ extends \n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.GeneratedMessageLite.\n"
+ " ExtendableMessageOrBuilder<\n"
+ " $classname$, $classname$.Builder> {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name(),
+ "idend", "");
} else {
printer->Print(
- "public interface $classname$OrBuilder extends\n"
- " $extra_interfaces$\n"
- " com.google.protobuf.MessageLiteOrBuilder {\n",
- "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
- "classname", descriptor_->name());
+ "public interface $classname$OrBuilder$idend$ extends\n"
+ " $extra_interfaces$\n"
+ " com.google.protobuf.MessageLiteOrBuilder {\n",
+ "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+ "classname", descriptor_->name(),
+ "idend", "");
}
+ printer->Annotate("classname", "idend", descriptor_);
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -163,9 +168,7 @@ void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
// ===================================================================
void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
- bool is_own_file =
- descriptor_->containing_type() == NULL &&
- MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+ bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
map<string, string> variables;
variables["static"] = is_own_file ? " " : " static ";
@@ -173,6 +176,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
WriteMessageDocComment(printer, descriptor_);
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+ /* immutable = */ true);
// The builder_type stores the super type name of the nested Builder class.
string builder_type;
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 292c1c56..1e319c6d 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -47,8 +47,7 @@ namespace java {
class ImmutableMessageLiteGenerator : public MessageGenerator {
public:
- explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor,
- Context* context);
+ ImmutableMessageLiteGenerator(const Descriptor* descriptor, Context* context);
virtual ~ImmutableMessageLiteGenerator();
virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_options.h b/src/google/protobuf/compiler/java/java_options.h
new file mode 100644
index 00000000..7bce1447
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_options.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generator options
+struct Options {
+ Options()
+ : generate_immutable_code(false),
+ generate_mutable_code(false),
+ generate_shared_code(false),
+ enforce_lite(false),
+ annotate_code(false) {
+ }
+
+ bool generate_immutable_code;
+ bool generate_mutable_code;
+ bool generate_shared_code;
+ // When set, the protoc will generate the current files and all the transitive
+ // dependencies as lite runtime.
+ bool enforce_lite;
+ // If true, we should build .meta files and emit @Generated annotations into
+ // generated code.
+ bool annotate_code;
+ // Name of a file where we will write a list of generated .meta file names,
+ // one per line.
+ string annotation_list_file;
+ // Name of a file where we will write a list of generated file names, one
+ // per line.
+ string output_list_file;
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index e42ec280..877baf0a 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -777,8 +777,8 @@ GenerateSerializationCode(io::Printer* printer) const {
// That makes it safe to rely on the memoized size here.
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ " output.writeUInt32NoTag($tag$);\n"
+ " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.write$capitalized_type$NoTag($name$_.get(i));\n"
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 690dad12..ad2db30c 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -63,22 +63,20 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
ClassNameResolver* name_resolver,
map<string, string>* variables) {
SetCommonFieldVariables(descriptor, info, variables);
-
- (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
- (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ JavaType javaType = GetJavaType(descriptor);
+ (*variables)["type"] = PrimitiveTypeName(javaType);
+ (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
- (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
- "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
(*variables)["capitalized_type"] =
GetCapitalizedType(descriptor, /* immutable = */ true);
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
- string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(
- GetJavaType(descriptor)), true /* cap_next_letter */);
- switch (GetJavaType(descriptor)) {
+ string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(javaType),
+ true /* cap_next_letter */);
+ switch (javaType) {
case JAVATYPE_INT:
case JAVATYPE_LONG:
case JAVATYPE_FLOAT:
@@ -112,7 +110,12 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["visit_type_list"] = "visitList";
}
- if (IsReferenceType(GetJavaType(descriptor))) {
+ if (javaType == JAVATYPE_BYTES) {
+ (*variables)["bytes_default"] =
+ ToUpper((*variables)["name"]) + "_DEFAULT_VALUE";
+ }
+
+ if (IsReferenceType(javaType)) {
(*variables)["null_check"] =
" if (value == null) {\n"
" throw new NullPointerException();\n"
@@ -204,6 +207,13 @@ GenerateInterfaceMembers(io::Printer* printer) const {
void ImmutablePrimitiveFieldLiteGenerator::
GenerateMembers(io::Printer* printer) const {
+ if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+ // allocate this once statically since we know ByteStrings are immutable
+ // values that can be reused.
+ printer->Print(
+ variables_,
+ "private static final $field_type$ $bytes_default$ = $default$;\n");
+ }
printer->Print(variables_,
"private $field_type$ $name$_;\n");
PrintExtraFieldInfo(variables_, printer);
@@ -287,7 +297,11 @@ GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
void ImmutablePrimitiveFieldLiteGenerator::
GenerateInitializationCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_ = $default$;\n");
+ if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+ printer->Print(variables_, "$name$_ = $bytes_default$;\n");
+ } else if (!IsDefaultValueJavaDefault(descriptor_)) {
+ printer->Print(variables_, "$name$_ = $default$;\n");
+ }
}
void ImmutablePrimitiveFieldLiteGenerator::
@@ -817,8 +831,8 @@ GenerateSerializationCode(io::Printer* printer) const {
// That makes it safe to rely on the memoized size here.
printer->Print(variables_,
"if (get$capitalized_name$List().size() > 0) {\n"
- " output.writeRawVarint32($tag$);\n"
- " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ " output.writeUInt32NoTag($tag$);\n"
+ " output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.write$capitalized_type$NoTag($repeated_get$(i));\n"
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 11bfc12d..9f34f010 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -60,9 +60,10 @@ ImmutableServiceGenerator::ImmutableServiceGenerator(
ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
void ImmutableServiceGenerator::Generate(io::Printer* printer) {
- bool is_own_file =
- MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+ bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
WriteServiceDocComment(printer, descriptor_);
+ MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+ /* immutable = */ true);
printer->Print(
"public $static$ abstract class $classname$\n"
" implements com.google.protobuf.Service {\n",
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
index 6707e821..5fc9e2f6 100644
--- a/src/google/protobuf/compiler/java/java_service.h
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -74,8 +74,8 @@ class ServiceGenerator {
class ImmutableServiceGenerator : public ServiceGenerator {
public:
- explicit ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
- Context* context);
+ ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
+ Context* context);
virtual ~ImmutableServiceGenerator();
virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 74253c3f..52893721 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -51,44 +51,53 @@ namespace protobuf {
namespace compiler {
namespace java {
-SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
- : name_resolver_(new ClassNameResolver),
- enforce_lite_(false),
- file_(file) {}
+SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file,
+ const Options& options)
+ : name_resolver_(new ClassNameResolver), file_(file), options_(options) {}
SharedCodeGenerator::~SharedCodeGenerator() {
}
void SharedCodeGenerator::Generate(GeneratorContext* context,
- vector<string>* file_list) {
+ vector<string>* file_list,
+ vector<string>* annotation_file_list) {
string java_package = FileJavaPackage(file_);
string package_dir = JavaPackageToDir(java_package);
- if (HasDescriptorMethods(file_, enforce_lite_)) {
+ if (HasDescriptorMethods(file_, options_.enforce_lite)) {
// Generate descriptors.
string classname = name_resolver_->GetDescriptorClassName(file_);
string filename = package_dir + classname + ".java";
file_list->push_back(filename);
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
- google::protobuf::scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$'));
-
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ google::protobuf::scoped_ptr<io::Printer> printer(
+ new io::Printer(output.get(), '$',
+ options_.annotate_code ? &annotation_collector : NULL));
+ string info_relative_path = classname + ".java.pb.meta";
+ string info_full_path = filename + ".pb.meta";
printer->Print(
- "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
- "// source: $filename$\n"
- "\n",
- "filename", file_->name());
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", file_->name());
if (!java_package.empty()) {
printer->Print(
"package $package$;\n"
"\n",
"package", java_package);
}
+ PrintGeneratedAnnotation(printer.get(), '$',
+ options_.annotate_code ? info_relative_path : "");
printer->Print(
- "public final class $classname$ {\n"
- " public static com.google.protobuf.Descriptors.FileDescriptor\n"
- " descriptor;\n"
- " static {\n",
- "classname", classname);
+ "public final class $classname$ {\n"
+ " public static com.google.protobuf.Descriptors.FileDescriptor\n"
+ " descriptor;\n"
+ " static {\n",
+ "classname", classname);
+ printer->Annotate("classname", file_->name());
printer->Indent();
printer->Indent();
GenerateDescriptors(printer.get());
@@ -98,6 +107,13 @@ void SharedCodeGenerator::Generate(GeneratorContext* context,
" }\n"
"}\n");
+ if (options_.annotate_code) {
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+ context->Open(info_full_path));
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ annotation_file_list->push_back(info_full_path);
+ }
+
printer.reset();
output.reset();
}
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
index 3b573c07..7e1e1f17 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.h
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -43,6 +43,7 @@
#include <vector>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
namespace google {
namespace protobuf {
@@ -66,15 +67,11 @@ namespace java {
// and mutable API. Currently only descriptors are shared.
class SharedCodeGenerator {
public:
- explicit SharedCodeGenerator(const FileDescriptor* file);
+ SharedCodeGenerator(const FileDescriptor* file, const Options& options);
~SharedCodeGenerator();
- void Generate(GeneratorContext* generator_context,
- vector<string>* file_list);
-
- void SetEnforceLite(bool value) {
- enforce_lite_ = value;
- }
+ void Generate(GeneratorContext* generator_context, vector<string>* file_list,
+ vector<string>* annotation_file_list);
void GenerateDescriptors(io::Printer* printer);
@@ -85,8 +82,8 @@ class SharedCodeGenerator {
bool ShouldIncludeDependency(const FileDescriptor* descriptor);
google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
- bool enforce_lite_;
const FileDescriptor* file_;
+ const Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
};
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index b67eeb53..b74c7447 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -712,7 +712,13 @@ void RepeatedImmutableStringFieldGenerator::
GenerateInterfaceMembers(io::Printer* printer) const {
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
- "$deprecation$com.google.protobuf.ProtocolStringList\n"
+ // NOTE: the same method in the implementation class actually returns
+ // com.google.protobuf.ProtocolStringList (a subclass of List). It's
+ // changed between protobuf 2.5.0 release and protobuf 2.6.1 release.
+ // To retain binary compatibilty with both 2.5.0 and 2.6.1 generated
+ // code, we make this interface method return List so both methods
+ // with different return types exist in the compiled byte code.
+ "$deprecation$java.util.List<java.lang.String>\n"
" get$capitalized_name$List();\n");
WriteFieldDocComment(printer, descriptor_);
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 8fb24bed..f5185ab1 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <google/protobuf/compiler/js/js_generator.h>
+#include "google/protobuf/compiler/js/js_generator.h"
#include <assert.h>
#include <algorithm>
@@ -444,6 +444,11 @@ bool IgnoreField(const FieldDescriptor* field) {
}
+// Do we ignore this message type?
+bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) {
+ return d->options().map_entry();
+}
+
// Does JSPB ignore this entire oneof? True only if all fields are ignored.
bool IgnoreOneof(const OneofDescriptor* oneof) {
for (int i = 0; i < oneof->field_count(); i++) {
@@ -454,7 +459,8 @@ bool IgnoreOneof(const OneofDescriptor* oneof) {
return true;
}
-string JSIdent(const FieldDescriptor* field,
+string JSIdent(const GeneratorOptions& options,
+ const FieldDescriptor* field,
bool is_upper_camel,
bool is_map) {
string result;
@@ -467,16 +473,20 @@ string JSIdent(const FieldDescriptor* field,
ToUpperCamel(ParseLowerUnderscore(field->name())) :
ToLowerCamel(ParseLowerUnderscore(field->name()));
}
- if (is_map) {
+ if (is_map || (field->is_map())) {
+ // JSPB-style or proto3-style map.
result += "Map";
} else if (field->is_repeated()) {
+ // Repeated field.
result += "List";
}
return result;
}
-string JSObjectFieldName(const FieldDescriptor* field) {
+string JSObjectFieldName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
string name = JSIdent(
+ options,
field,
/* is_upper_camel = */ false,
/* is_map = */ false);
@@ -502,9 +512,10 @@ string JSByteGetterSuffix(BytesMode bytes_mode) {
// Returns the field name as a capitalized portion of a getter/setter method
// name, e.g. MyField for .getMyField().
-string JSGetterName(const FieldDescriptor* field,
+string JSGetterName(const GeneratorOptions& options,
+ const FieldDescriptor* field,
BytesMode bytes_mode = BYTES_DEFAULT) {
- string name = JSIdent(field,
+ string name = JSIdent(options, field,
/* is_upper_camel = */ true,
/* is_map = */ false);
if (field->type() == FieldDescriptor::TYPE_BYTES) {
@@ -520,8 +531,9 @@ string JSGetterName(const FieldDescriptor* field,
return name;
}
-string JSMapGetterName(const FieldDescriptor* field) {
- return JSIdent(field,
+string JSMapGetterName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ return JSIdent(options, field,
/* is_upper_camel = */ true,
/* is_map = */ true);
}
@@ -967,12 +979,24 @@ string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
return name;
}
-string JSBinaryReaderMethodName(const FieldDescriptor* field) {
- return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+string JSBinaryReaderMethodName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ if (options.binary) {
+ return "jspb.BinaryReader.prototype.read" +
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+ } else {
+ return "null";
+ }
}
-string JSBinaryWriterMethodName(const FieldDescriptor* field) {
- return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+string JSBinaryWriterMethodName(const GeneratorOptions& options,
+ const FieldDescriptor* field) {
+ if (options.binary) {
+ return "jspb.BinaryWriter.prototype.write" +
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+ } else {
+ return "null";
+ }
}
string JSReturnClause(const FieldDescriptor* desc) {
@@ -986,7 +1010,7 @@ string JSReturnDoc(const GeneratorOptions& options,
bool HasRepeatedFields(const Descriptor* desc) {
for (int i = 0; i < desc->field_count(); i++) {
- if (desc->field(i)->is_repeated()) {
+ if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
return true;
}
}
@@ -1021,7 +1045,7 @@ string OneofFieldsArrayName(const GeneratorOptions& options,
string RepeatedFieldNumberList(const Descriptor* desc) {
std::vector<string> numbers;
for (int i = 0; i < desc->field_count(); i++) {
- if (desc->field(i)->is_repeated()) {
+ if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
numbers.push_back(JSFieldIndex(desc->field(i)));
}
}
@@ -1092,27 +1116,58 @@ string JSExtensionsObjectName(const GeneratorOptions& options,
}
}
+static const int kMapKeyField = 1;
+static const int kMapValueField = 2;
+
+const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
+ assert(field->is_map());
+ return field->message_type()->FindFieldByNumber(kMapKeyField);
+}
+
+const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
+ assert(field->is_map());
+ return field->message_type()->FindFieldByNumber(kMapValueField);
+}
+
string FieldDefinition(const GeneratorOptions& options,
const FieldDescriptor* field) {
- string qualifier = field->is_repeated() ? "repeated" :
- (field->is_optional() ? "optional" : "required");
- string type, name;
- if (field->type() == FieldDescriptor::TYPE_ENUM ||
- field->type() == FieldDescriptor::TYPE_MESSAGE) {
- type = RelativeTypeName(field);
- name = field->name();
- } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
- type = "group";
- name = field->message_type()->name();
+ if (field->is_map()) {
+ const FieldDescriptor* key_field = MapFieldKey(field);
+ const FieldDescriptor* value_field = MapFieldValue(field);
+ string key_type = ProtoTypeName(options, key_field);
+ string value_type;
+ if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
+ value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ value_type = RelativeTypeName(value_field);
+ } else {
+ value_type = ProtoTypeName(options, value_field);
+ }
+ return StringPrintf("map<%s, %s> %s = %d;",
+ key_type.c_str(),
+ value_type.c_str(),
+ field->name().c_str(),
+ field->number());
} else {
- type = ProtoTypeName(options, field);
- name = field->name();
+ string qualifier = field->is_repeated() ? "repeated" :
+ (field->is_optional() ? "optional" : "required");
+ string type, name;
+ if (field->type() == FieldDescriptor::TYPE_ENUM ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ type = RelativeTypeName(field);
+ name = field->name();
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ type = "group";
+ name = field->message_type()->name();
+ } else {
+ type = ProtoTypeName(options, field);
+ name = field->name();
+ }
+ return StringPrintf("%s %s %s = %d;",
+ qualifier.c_str(),
+ type.c_str(),
+ name.c_str(),
+ field->number());
}
- return StringPrintf("%s %s %s = %d;",
- qualifier.c_str(),
- type.c_str(),
- name.c_str(),
- field->number());
}
string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
@@ -1417,6 +1472,10 @@ void Generator::FindProvidesForMessage(
io::Printer* printer,
const Descriptor* desc,
std::set<string>* provided) const {
+ if (IgnoreMessage(options, desc)) {
+ return;
+ }
+
string name = GetPath(options, desc);
provided->insert(name);
@@ -1451,7 +1510,8 @@ void Generator::FindProvidesForFields(
}
string name =
- GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+ GetPath(options, field->file()) + "." +
+ JSObjectFieldName(options, field);
provided->insert(name);
}
}
@@ -1494,10 +1554,13 @@ void Generator::GenerateRequiresForLibrary(
for (int i = 0; i < files.size(); i++) {
for (int j = 0; j < files[i]->message_type_count(); j++) {
- FindRequiresForMessage(options,
- files[i]->message_type(j),
- &required, &forwards, &have_message);
+ const Descriptor* desc = files[i]->message_type(j);
+ if (!IgnoreMessage(options, desc)) {
+ FindRequiresForMessage(options, desc, &required, &forwards,
+ &have_message);
+ }
}
+
if (!have_extensions && HasExtensions(files[i])) {
have_extensions = true;
}
@@ -1632,7 +1695,9 @@ void Generator::FindRequiresForField(const GeneratorOptions& options,
forwards->insert(GetPath(options, field->enum_type()));
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- required->insert(GetPath(options, field->message_type()));
+ if (!IgnoreMessage(options, field->message_type())) {
+ required->insert(GetPath(options, field->message_type()));
+ }
}
}
@@ -1668,6 +1733,10 @@ void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
void Generator::GenerateClass(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
+ if (IgnoreMessage(options, desc)) {
+ return;
+ }
+
if (!NamespaceOnly(desc)) {
printer->Print("\n");
GenerateClassConstructor(options, printer, desc);
@@ -1932,21 +2001,24 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
printer->Print("$fieldname$: ",
- "fieldname", JSObjectFieldName(field));
+ "fieldname", JSObjectFieldName(options, field));
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_map()) {
+ printer->Print("(f = msg.get$name$(true)) ? f.toArray() : []",
+ "name", JSGetterName(options, field));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field.
if (field->is_repeated()) {
{
printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
" $type$.toObject, includeInstance)",
- "getter", JSGetterName(field),
+ "getter", JSGetterName(options, field),
"type", SubmessageTypeRef(options, field));
}
} else {
printer->Print("(f = msg.get$getter$()) && "
"$type$.toObject(includeInstance, f)",
- "getter", JSGetterName(field),
+ "getter", JSGetterName(options, field),
"type", SubmessageTypeRef(options, field));
}
} else {
@@ -1956,7 +2028,7 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
// Delegate to the generated get<field>() method in order not to duplicate
// the proto3-field-default-value or byte-coercion logic here.
printer->Print("msg.get$getter$()",
- "getter", JSGetterName(field, BYTES_B64));
+ "getter", JSGetterName(options, field, BYTES_B64));
} else {
if (field->has_default_value()) {
printer->Print("jspb.Message.getField(msg, $index$) == null ? "
@@ -2017,7 +2089,17 @@ void Generator::GenerateClassFieldFromObject(
const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+ if (field->is_map()) {
+ // `msg` is a newly-constructed message object that has not yet built any
+ // map containers wrapping underlying arrays, so we can simply directly set
+ // the array here without fear of a stale wrapper.
+ printer->Print(
+ " goog.isDef(obj.$name$) && "
+ "jspb.Message.setField(msg, $index$, obj.$name$);\n",
+ "name", JSObjectFieldName(options, field),
+ "index", JSFieldIndex(field));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field (singular or repeated)
if (field->is_repeated()) {
{
@@ -2027,7 +2109,7 @@ void Generator::GenerateClassFieldFromObject(
" msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
" return $fieldclass$.fromObject(i);\n"
" }));\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2035,7 +2117,7 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
" msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2044,7 +2126,7 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
"obj.$name$);\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"index", JSFieldIndex(field));
}
}
@@ -2114,17 +2196,93 @@ void GenerateBytesWrapper(const GeneratorOptions& options,
"comment", FieldComments(field, bytes_mode),
"type", type,
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field, bytes_mode),
+ "name", JSGetterName(options, field, bytes_mode),
"list", field->is_repeated() ? "List" : "",
"suffix", JSByteGetterSuffix(bytes_mode),
- "defname", JSGetterName(field, BYTES_DEFAULT));
+ "defname", JSGetterName(options, field, BYTES_DEFAULT));
}
void Generator::GenerateClassField(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->is_map()) {
+ const FieldDescriptor* key_field = MapFieldKey(field);
+ const FieldDescriptor* value_field = MapFieldValue(field);
+ // Map field: special handling to instantiate the map object on demand.
+ string key_type =
+ JSFieldTypeAnnotation(
+ options, key_field,
+ /* force_optional = */ false,
+ /* force_present = */ true,
+ /* singular_if_not_packed = */ false);
+ string value_type =
+ JSFieldTypeAnnotation(
+ options, value_field,
+ /* force_optional = */ false,
+ /* force_present = */ true,
+ /* singular_if_not_packed = */ false);
+
+ printer->Print(
+ "/**\n"
+ " * $fielddef$\n"
+ " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
+ " * empty, instead returning `undefined`\n"
+ " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
+ " */\n",
+ "fielddef", FieldDefinition(options, field),
+ "keytype", key_type,
+ "valuetype", value_type);
+ printer->Print(
+ "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n"
+ " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(options, field),
+ "keytype", key_type,
+ "valuetype", value_type);
+ printer->Print(
+ " jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
+ "index", JSFieldIndex(field));
+
+ if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(",\n"
+ " $messageType$",
+ "messageType", GetPath(options, value_field->message_type()));
+ } else if (options.binary) {
+ printer->Print(",\n"
+ " null");
+ }
+
+ if (options.binary) {
+ printer->Print(",\n"
+ " $keyWriterFn$,\n"
+ " $keyReaderFn$,\n"
+ " $valueWriterFn$,\n"
+ " $valueReaderFn$",
+ "keyWriterFn", JSBinaryWriterMethodName(options, key_field),
+ "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
+ "valueWriterFn", JSBinaryWriterMethodName(options, value_field),
+ "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
+
+ if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ printer->Print(",\n"
+ " $messageType$.serializeBinaryToWriter,\n"
+ " $messageType$.deserializeBinaryFromReader",
+ "messageType", GetPath(options, value_field->message_type()));
+ }
+ }
+
+ printer->Print(
+ "));\n");
+
+ printer->Print(
+ "};\n"
+ "\n"
+ "\n");
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Message field: special handling in order to wrap the underlying data
+ // array with a message object.
+
printer->Print(
"/**\n"
" * $fielddef$\n"
@@ -2146,7 +2304,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n"
"\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"type", JSFieldTypeAnnotation(options, field,
/* force_optional = */ false,
/* force_present = */ false,
@@ -2167,7 +2325,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
/* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field),
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"repeatedtag", (field->is_repeated() ? "Repeated" : ""));
@@ -2188,7 +2346,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n"
"\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
"returnvalue", JSReturnClause(field));
@@ -2230,7 +2388,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
printer->Print(
"$class$.prototype.get$name$ = function() {\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field));
+ "name", JSGetterName(options, field));
if (untyped) {
printer->Print(
@@ -2315,7 +2473,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"$class$.prototype.set$name$ = function(value) {\n"
" jspb.Message.set$oneoftag$Field(this, $index$",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"index", JSFieldIndex(field));
printer->Print(
@@ -2345,7 +2503,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"$class$.prototype.clear$name$ = function() {\n"
" jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(field),
+ "name", JSGetterName(options, field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"oneofgroup", (field->containing_oneof() ?
(", " + JSOneofArray(options, field)) : ""),
@@ -2461,40 +2619,49 @@ void Generator::GenerateClassDeserializeBinaryField(
printer->Print(" case $num$:\n",
"num", SimpleItoa(field->number()));
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- printer->Print(
- " var value = new $fieldclass$;\n"
- " reader.read$msgOrGroup$($grpfield$value,"
- "$fieldclass$.deserializeBinaryFromReader);\n",
- "fieldclass", SubmessageTypeRef(options, field),
- "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
- "Group" : "Message",
- "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
- (SimpleItoa(field->number()) + ", ") : "");
- } else {
+ if (field->is_map()) {
printer->Print(
- " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
- "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
- /* singular_if_not_packed = */ true,
- BYTES_U8),
- "reader", JSBinaryReaderMethodName(field));
- }
-
- if (field->is_repeated() && !field->is_packed()) {
- // Repeated fields receive a |value| one at at a time; append to array
- // returned by get$name$(). Annoyingly, we have to call 'set' after
- // changing the array.
- printer->Print(" msg.get$name$().push(value);\n", "name",
- JSGetterName(field));
- printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
- JSGetterName(field));
+ " var value = msg.get$name$();\n"
+ " reader.readMessage(value, jspb.Map.deserializeBinary);\n",
+ "name", JSGetterName(options, field));
} else {
- // Singular fields, and packed repeated fields, receive a |value| either as
- // the field's value or as the array of all the field's values; set this as
- // the field's value directly.
- printer->Print(
- " msg.set$name$(value);\n",
- "name", JSGetterName(field));
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ printer->Print(
+ " var value = new $fieldclass$;\n"
+ " reader.read$msgOrGroup$($grpfield$value,"
+ "$fieldclass$.deserializeBinaryFromReader);\n",
+ "fieldclass", SubmessageTypeRef(options, field),
+ "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ "Group" : "Message",
+ "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+ (SimpleItoa(field->number()) + ", ") : "");
+ } else {
+ printer->Print(
+ " var value = /** @type {$fieldtype$} */ "
+ "(reader.read$reader$());\n",
+ "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+ /* singular_if_not_packed */ true,
+ BYTES_U8),
+ "reader",
+ JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
+ }
+
+ if (field->is_repeated() && !field->is_packed()) {
+ // Repeated fields receive a |value| one at at a time; append to array
+ // returned by get$name$(). Annoyingly, we have to call 'set' after
+ // changing the array.
+ printer->Print(" msg.get$name$().push(value);\n", "name",
+ JSGetterName(options, field));
+ printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
+ JSGetterName(options, field));
+ } else {
+ // Singular fields, and packed repeated fields, receive a |value| either
+ // as the field's value or as the array of all the field's values; set
+ // this as the field's value directly.
+ printer->Print(
+ " msg.set$name$(value);\n",
+ "name", JSGetterName(options, field));
+ }
}
printer->Print(" break;\n");
@@ -2559,10 +2726,18 @@ void Generator::GenerateClassSerializeBinaryField(
io::Printer* printer,
const FieldDescriptor* field) const {
printer->Print(
- " f = this.get$name$();\n",
- "name", JSGetterName(field, BYTES_U8));
+ " f = this.get$name$($nolazy$);\n",
+ "name", JSGetterName(options, field, BYTES_U8),
+ // No lazy creation for maps containers -- fastpath the empty case.
+ "nolazy", (field->is_map()) ? "true" : "");
- if (field->is_repeated()) {
+
+ // Print an `if (condition)` statement that evaluates to true if the field
+ // goes on the wire.
+ if (field->is_map()) {
+ printer->Print(
+ " if (f && f.getLength() > 0) {\n");
+ } else if (field->is_repeated()) {
printer->Print(
" if (f.length > 0) {\n");
} else {
@@ -2605,23 +2780,35 @@ void Generator::GenerateClassSerializeBinaryField(
}
}
- printer->Print(
- " writer.$writer$(\n"
- " $index$,\n"
- " f",
- "writer", JSBinaryWriterMethodName(field),
- "index", SimpleItoa(field->number()));
-
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Write the field on the wire.
+ if (field->is_map()) {
printer->Print(
- ",\n"
- " $submsg$.serializeBinaryToWriter\n",
- "submsg", SubmessageTypeRef(options, field));
+ " f.serializeBinary($index$, writer);\n",
+ "index", SimpleItoa(field->number()));
} else {
- printer->Print("\n");
+ printer->Print(
+ " writer.write$method$(\n"
+ " $index$,\n"
+ " f",
+ "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
+ "index", SimpleItoa(field->number()));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ !(field->is_map())) {
+ printer->Print(
+ ",\n"
+ " $submsg$.serializeBinaryToWriter\n",
+ "submsg", SubmessageTypeRef(options, field));
+ } else {
+ printer->Print("\n");
+ }
+
+ printer->Print(
+ " );\n");
}
+
+ // Close the `if`.
printer->Print(
- " );\n"
" }\n");
}
@@ -2665,7 +2852,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
" */\n"
"$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"class", extension_scope,
"extensionType", JSFieldTypeAnnotation(
options, field,
@@ -2681,7 +2868,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" $toObject$),\n"
" $repeated$",
"index", SimpleItoa(field->number()),
- "name", JSObjectFieldName(field),
+ "name", JSObjectFieldName(options, field),
"ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
SubmessageTypeRef(options, field) : string("null")),
"toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
@@ -2692,13 +2879,13 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
if (options.binary) {
printer->Print(
",\n"
- " jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
- " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+ " $binaryReaderFn$,\n"
+ " $binaryWriterFn$,\n"
" $binaryMessageSerializeFn$,\n"
" $binaryMessageDeserializeFn$,\n"
" $isPacked$);\n",
- "binaryReaderFn", JSBinaryReaderMethodName(field),
- "binaryWriterFn", JSBinaryWriterMethodName(field),
+ "binaryReaderFn", JSBinaryReaderMethodName(options, field),
+ "binaryWriterFn", JSBinaryWriterMethodName(options, field),
"binaryMessageSerializeFn",
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
(SubmessageTypeRef(options, field) +
@@ -2721,7 +2908,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
field->containing_type()),
"index", SimpleItoa(field->number()),
"class", extension_scope,
- "name", JSObjectFieldName(field));
+ "name", JSObjectFieldName(options, field));
}
bool GeneratorOptions::ParseFromOptions(
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 66ad13b7..2f3c5b8f 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -35,6 +35,8 @@
#include <google/protobuf/compiler/python/python_generator.h>
#include <google/protobuf/compiler/java/java_generator.h>
#include <google/protobuf/compiler/javanano/javanano_generator.h>
+// TODO(teboring): Add it back when php implementation is ready
+// #include <google/protobuf/compiler/php/php_generator.h>
#include <google/protobuf/compiler/ruby/ruby_generator.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
@@ -66,6 +68,12 @@ int main(int argc, char* argv[]) {
cli.RegisterGenerator("--javanano_out", &javanano_generator,
"Generate Java Nano source file.");
+ // TODO(teboring): Add it back when php implementation is ready
+ // PHP
+ // google::protobuf::compiler::php::Generator php_generator;
+ // cli.RegisterGenerator("--php_out", &php_generator,
+ // "Generate PHP source file.");
+
// Ruby
google::protobuf::compiler::ruby::Generator rb_generator;
cli.RegisterGenerator("--ruby_out", &rb_generator,
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 90ded4de..214d7c9c 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -1630,6 +1630,16 @@ bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl,
return false;
}
+ if (LookingAt("option")) {
+ LocationRecorder option_location(
+ oneof_location, OneofDescriptorProto::kOptionsFieldNumber);
+ if (!ParseOption(oneof_decl->mutable_options(), option_location,
+ containing_file, OPTION_STATEMENT)) {
+ return false;
+ }
+ continue;
+ }
+
// Print a nice error if the user accidentally tries to place a label
// on an individual member of a oneof.
if (LookingAt("required") ||
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index e9d50a1d..c4d48fc6 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -373,8 +373,8 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorRequest)
}
-::google::protobuf::uint8* CodeGeneratorRequest::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorRequest::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
// repeated string file_to_generate = 1;
for (int i = 0; i < this->file_to_generate_size(); i++) {
@@ -400,8 +400,8 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 15, this->proto_file(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 15, this->proto_file(i), false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -878,8 +878,8 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse.File)
}
-::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorResponse_File::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
// optional string name = 1;
if (has_name()) {
@@ -1208,8 +1208,8 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse)
}
-::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorResponse::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
// optional string error = 1;
if (has_error()) {
@@ -1225,8 +1225,8 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 15, this->file(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 15, this->file(i), false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 510202f0..13eeb69f 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -45,7 +45,7 @@ class CodeGeneratorResponse_File;
// ===================================================================
-class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorRequest) */ {
public:
CodeGeneratorRequest();
virtual ~CodeGeneratorRequest();
@@ -87,7 +87,11 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -169,7 +173,7 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
};
// -------------------------------------------------------------------
-class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse.File) */ {
public:
CodeGeneratorResponse_File();
virtual ~CodeGeneratorResponse_File();
@@ -211,7 +215,11 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -293,7 +301,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
};
// -------------------------------------------------------------------
-class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse) */ {
public:
CodeGeneratorResponse();
virtual ~CodeGeneratorResponse();
@@ -335,7 +343,11 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 0553dd0d..cc54a8ab 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -707,11 +707,18 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
m["name"] = desc->name();
m["full_name"] = desc->full_name();
m["index"] = SimpleItoa(desc->index());
+ string options_string =
+ OptionsValue("OneofOptions", desc->options().SerializeAsString());
+ if (options_string == "None") {
+ m["options"] = "";
+ } else {
+ m["options"] = ", options=" + options_string;
+ }
printer_->Print(
m,
"_descriptor.OneofDescriptor(\n"
" name='$name$', full_name='$full_name$',\n"
- " index=$index$, containing_type=None, fields=[]),\n");
+ " index=$index$, containing_type=None, fields=[]$options$),\n");
}
printer_->Outdent();
printer_->Print("],\n");
@@ -1235,6 +1242,18 @@ void Generator::FixAllDescriptorOptions() const {
}
}
+void Generator::FixOptionsForOneof(const OneofDescriptor& oneof) const {
+ string oneof_options = OptionsValue(
+ "OneofOptions", oneof.options().SerializeAsString());
+ if (oneof_options != "None") {
+ string oneof_name = strings::Substitute(
+ "$0.$1['$2']",
+ ModuleLevelDescriptorName(*oneof.containing_type()),
+ "oneofs_by_name", oneof.name());
+ PrintDescriptorOptionsFixingCode(oneof_name, oneof_options, printer_);
+ }
+}
+
// Prints expressions that set the options for an enum descriptor and its
// value descriptors.
void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
@@ -1288,6 +1307,10 @@ void Generator::FixOptionsForMessage(const Descriptor& descriptor) const {
for (int i = 0; i < descriptor.nested_type_count(); ++i) {
FixOptionsForMessage(*descriptor.nested_type(i));
}
+ // Oneofs.
+ for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+ FixOptionsForOneof(*descriptor.oneof_decl(i));
+ }
// Enums.
for (int i = 0; i < descriptor.enum_type_count(); ++i) {
FixOptionsForEnum(*descriptor.enum_type(i));
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index aa0f5fce..7583aa65 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -48,6 +48,7 @@ class Descriptor;
class EnumDescriptor;
class EnumValueDescriptor;
class FieldDescriptor;
+class OneofDescriptor;
class ServiceDescriptor;
namespace io { class Printer; }
@@ -148,6 +149,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator {
void FixAllDescriptorOptions() const;
void FixOptionsForField(const FieldDescriptor& field) const;
+ void FixOptionsForOneof(const OneofDescriptor& oneof) const;
void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
void FixOptionsForMessage(const Descriptor& descriptor) const;
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index 1b04cb32..c0acb407 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -45,22 +45,8 @@ namespace compiler {
namespace ruby {
namespace {
-string FindRubyTestDir(const string& file) {
- // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
-#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
- string prefix = ".";
- while (!File::Exists(prefix + "/src/google/protobuf/compiler/ruby" + file)) {
- if (!File::Exists(prefix)) {
- GOOGLE_LOG(FATAL)
- << "Could not find Ruby test directory. Please run tests from "
- "somewhere within the protobuf source package.";
- }
- prefix += "/..";
- }
- return prefix + "/src/google/protobuf/compiler/ruby";
-#else
- return "third_party/protobuf/src/google/protobuf/compiler/ruby";
-#endif // GOOGLE_THIRD_PARTY_PROTOBUF
+string FindRubyTestDir() {
+ return TestSourceDir() + "/google/protobuf/compiler/ruby";
}
// This test is a simple golden-file test over the output of the Ruby code
@@ -71,7 +57,7 @@ string FindRubyTestDir(const string& file) {
// extensions to the point where we can do this test in a more automated way.
TEST(RubyGeneratorTest, GeneratorTest) {
- string ruby_tests = FindRubyTestDir("/ruby_generated_code.proto");
+ string ruby_tests = FindRubyTestDir();
google::protobuf::compiler::CommandLineInterface cli;
cli.SetInputsAreProtoPathRelative(true);
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 56e11fa9..9b20946c 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1896,6 +1896,9 @@ void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
proto->set_name(name());
+ if (&options() != &OneofOptions::default_instance()) {
+ proto->mutable_options()->CopyFrom(options());
+ }
}
void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
@@ -2435,6 +2438,9 @@ void OneofDescriptor::DebugString(int depth, string* contents,
comment_printer.AddPreComment(contents);
strings::SubstituteAndAppend(
contents, "$0 oneof $1 {", prefix, name());
+
+ FormatLineOptions(depth, options(), contents);
+
if (debug_string_options.elide_oneof_body) {
contents->append(" ... }\n");
} else {
@@ -4523,6 +4529,13 @@ void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
result->field_count_ = 0;
result->fields_ = NULL;
+ // Copy options.
+ if (!proto.has_options()) {
+ result->options_ = NULL; // Will set to default_instance later.
+ } else {
+ AllocateOptions(proto.options(), result);
+ }
+
AddSymbol(result->full_name(), parent, result->name(),
proto, Symbol(result));
}
@@ -4783,6 +4796,10 @@ void DescriptorBuilder::CrossLinkMessage(
oneof_decl->fields_ =
tables_->AllocateArray<const FieldDescriptor*>(oneof_decl->field_count_);
oneof_decl->field_count_ = 0;
+
+ if (oneof_decl->options_ == NULL) {
+ oneof_decl->options_ = &OneofOptions::default_instance();
+ }
}
// Then fill them in.
@@ -5181,7 +5198,7 @@ void DescriptorBuilder::ValidateProto3Message(
if (name_to_field.find(lowercase_name) != name_to_field.end()) {
AddError(message->full_name(), proto,
DescriptorPool::ErrorCollector::OTHER,
- "The JSON camcel-case name of field \"" +
+ "The JSON camel-case name of field \"" +
message->field(i)->name() + "\" conflicts with field \"" +
name_to_field[lowercase_name]->name() + "\". This is not " +
"allowed in proto3.");
@@ -5237,6 +5254,7 @@ void DescriptorBuilder::ValidateProto3Enum(
}
}
+
void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
const DescriptorProto& proto) {
VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field);
@@ -5257,6 +5275,7 @@ void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
max_extension_range));
}
}
+
}
void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 3ecc0a9c..b040b62c 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -62,7 +62,6 @@
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
#ifdef TYPE_BOOL
@@ -95,6 +94,7 @@ class MethodDescriptorProto;
class FileDescriptorProto;
class MessageOptions;
class FieldOptions;
+class OneofOptions;
class EnumOptions;
class EnumValueOptions;
class ServiceOptions;
@@ -750,6 +750,8 @@ class LIBPROTOBUF_EXPORT OneofDescriptor {
// .proto file. Does not include extensions.
const FieldDescriptor* field(int index) const;
+ const OneofOptions& options() const;
+
// See Descriptor::CopyTo().
void CopyTo(OneofDescriptorProto* proto) const;
@@ -767,6 +769,8 @@ class LIBPROTOBUF_EXPORT OneofDescriptor {
bool GetSourceLocation(SourceLocation* out_location) const;
private:
+ typedef OneofOptions OptionsType;
+
// Allows access to GetLocationPath for annotations.
friend class ::google::protobuf::io::Printer;
@@ -784,6 +788,8 @@ class LIBPROTOBUF_EXPORT OneofDescriptor {
bool is_extendable_;
int field_count_;
const FieldDescriptor** fields_;
+ const OneofOptions* options_;
+
// IMPORTANT: If you add a new field, make sure to search for all instances
// of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
// in descriptor.cc and update them to initialize the field.
@@ -1708,6 +1714,7 @@ PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, full_name)
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name)
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 4d5c4d99..4e2c9dcf 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -69,6 +69,9 @@ const ::google::protobuf::internal::GeneratedMessageReflection*
FieldOptions_reflection_ = NULL;
const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL;
const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* OneofOptions_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ OneofOptions_reflection_ = NULL;
const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
EnumOptions_reflection_ = NULL;
@@ -233,8 +236,9 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0);
FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1);
OneofDescriptorProto_descriptor_ = file->message_type(4);
- static const int OneofDescriptorProto_offsets_[1] = {
+ static const int OneofDescriptorProto_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, options_),
};
OneofDescriptorProto_reflection_ =
::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -390,7 +394,22 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
-1);
FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
FieldOptions_JSType_descriptor_ = FieldOptions_descriptor_->enum_type(1);
- EnumOptions_descriptor_ = file->message_type(12);
+ OneofOptions_descriptor_ = file->message_type(12);
+ static const int OneofOptions_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, uninterpreted_option_),
+ };
+ OneofOptions_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ OneofOptions_descriptor_,
+ OneofOptions::default_instance_,
+ OneofOptions_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _has_bits_[0]),
+ -1,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _extensions_),
+ sizeof(OneofOptions),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _internal_metadata_),
+ -1);
+ EnumOptions_descriptor_ = file->message_type(13);
static const int EnumOptions_offsets_[3] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, deprecated_),
@@ -407,7 +426,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(EnumOptions),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_),
-1);
- EnumValueOptions_descriptor_ = file->message_type(13);
+ EnumValueOptions_descriptor_ = file->message_type(14);
static const int EnumValueOptions_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_),
@@ -423,7 +442,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(EnumValueOptions),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_),
-1);
- ServiceOptions_descriptor_ = file->message_type(14);
+ ServiceOptions_descriptor_ = file->message_type(15);
static const int ServiceOptions_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_),
@@ -439,7 +458,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(ServiceOptions),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_),
-1);
- MethodOptions_descriptor_ = file->message_type(15);
+ MethodOptions_descriptor_ = file->message_type(16);
static const int MethodOptions_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_),
@@ -455,7 +474,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(MethodOptions),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_),
-1);
- UninterpretedOption_descriptor_ = file->message_type(16);
+ UninterpretedOption_descriptor_ = file->message_type(17);
static const int UninterpretedOption_offsets_[7] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, identifier_value_),
@@ -492,7 +511,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(UninterpretedOption_NamePart),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_),
-1);
- SourceCodeInfo_descriptor_ = file->message_type(17);
+ SourceCodeInfo_descriptor_ = file->message_type(18);
static const int SourceCodeInfo_offsets_[1] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_),
};
@@ -526,7 +545,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
sizeof(SourceCodeInfo_Location),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_),
-1);
- GeneratedCodeInfo_descriptor_ = file->message_type(18);
+ GeneratedCodeInfo_descriptor_ = file->message_type(19);
static const int GeneratedCodeInfo_offsets_[1] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, annotation_),
};
@@ -600,6 +619,8 @@ void protobuf_RegisterTypes(const ::std::string&) {
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
FieldOptions_descriptor_, &FieldOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ OneofOptions_descriptor_, &OneofOptions::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
EnumOptions_descriptor_, &EnumOptions::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
@@ -652,6 +673,8 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() {
delete MessageOptions_reflection_;
delete FieldOptions::default_instance_;
delete FieldOptions_reflection_;
+ delete OneofOptions::default_instance_;
+ delete OneofOptions_reflection_;
delete EnumOptions::default_instance_;
delete EnumOptions_reflection_;
delete EnumValueOptions::default_instance_;
@@ -729,87 +752,91 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
"SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI"
"NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE"
"L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE"
- "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004"
- "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na"
- "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu"
- "f.EnumValueDescriptorProto\022-\n\007options\030\003 "
- "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu"
- "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n"
- "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr"
- "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr"
- "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013"
- "2&.google.protobuf.MethodDescriptorProto"
- "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv"
- "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004"
- "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output"
- "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr"
- "otobuf.MethodOptions\022\037\n\020client_streaming"
- "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:"
- "\005false\"\207\005\n\013FileOptions\022\024\n\014java_package\030\001"
- " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja"
- "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g"
- "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026"
- "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o"
- "ptimize_for\030\t \001(\0162).google.protobuf.File"
- "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag"
- "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa"
- "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals"
- "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n"
- "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar"
- "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$"
- " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024uninte"
- "rpreted_option\030\347\007 \003(\0132$.google.protobuf."
- "UninterpretedOption\":\n\014OptimizeMode\022\t\n\005S"
- "PEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*"
- "\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOptions\022&\n\027m"
- "essage_set_wire_format\030\001 \001(\010:\005false\022.\n\037n"
- "o_standard_descriptor_accessor\030\002 \001(\010:\005fa"
- "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_en"
- "try\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\013"
- "2$.google.protobuf.UninterpretedOption*\t"
- "\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001("
- "\0162#.google.protobuf.FieldOptions.CType:\006"
- "STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$"
- ".google.protobuf.FieldOptions.JSType:\tJS"
- "_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecat"
- "ed\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024"
- "uninterpreted_option\030\347\007 \003(\0132$.google.pro"
- "tobuf.UninterpretedOption\"/\n\005CType\022\n\n\006ST"
- "RING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JS"
- "Type\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS"
- "_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013"
- "allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f"
+ "L_REPEATED\020\003\"T\n\024OneofDescriptorProto\022\014\n\004"
+ "name\030\001 \001(\t\022.\n\007options\030\002 \001(\0132\035.google.pro"
+ "tobuf.OneofOptions\"\214\001\n\023EnumDescriptorPro"
+ "to\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google"
+ ".protobuf.EnumValueDescriptorProto\022-\n\007op"
+ "tions\030\003 \001(\0132\034.google.protobuf.EnumOption"
+ "s\"l\n\030EnumValueDescriptorProto\022\014\n\004name\030\001 "
+ "\001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.g"
+ "oogle.protobuf.EnumValueOptions\"\220\001\n\026Serv"
+ "iceDescriptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006meth"
+ "od\030\002 \003(\0132&.google.protobuf.MethodDescrip"
+ "torProto\0220\n\007options\030\003 \001(\0132\037.google.proto"
+ "buf.ServiceOptions\"\301\001\n\025MethodDescriptorP"
+ "roto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023"
+ "\n\013output_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.g"
+ "oogle.protobuf.MethodOptions\022\037\n\020client_s"
+ "treaming\030\005 \001(\010:\005false\022\037\n\020server_streamin"
+ "g\030\006 \001(\010:\005false\"\207\005\n\013FileOptions\022\024\n\014java_p"
+ "ackage\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001"
+ "(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022,"
+ "\n\035java_generate_equals_and_hash\030\024 \001(\010:\005f"
+ "alse\022%\n\026java_string_check_utf8\030\033 \001(\010:\005fa"
+ "lse\022F\n\014optimize_for\030\t \001(\0162).google.proto"
+ "buf.FileOptions.OptimizeMode:\005SPEED\022\022\n\ng"
+ "o_package\030\013 \001(\t\022\"\n\023cc_generic_services\030\020"
+ " \001(\010:\005false\022$\n\025java_generic_services\030\021 \001"
+ "(\010:\005false\022\"\n\023py_generic_services\030\022 \001(\010:\005"
+ "false\022\031\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_e"
+ "nable_arenas\030\037 \001(\010:\005false\022\031\n\021objc_class_"
+ "prefix\030$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C"
+ "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p"
+ "rotobuf.UninterpretedOption\":\n\014OptimizeM"
+ "ode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RU"
+ "NTIME\020\003*\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOpti"
+ "ons\022&\n\027message_set_wire_format\030\001 \001(\010:\005fa"
+ "lse\022.\n\037no_standard_descriptor_accessor\030\002"
+ " \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021"
+ "\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpreted_optio"
+ "n\030\347\007 \003(\0132$.google.protobuf.Uninterpreted"
+ "Option*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ct"
+ "ype\030\001 \001(\0162#.google.protobuf.FieldOptions"
+ ".CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype"
+ "\030\006 \001(\0162$.google.protobuf.FieldOptions.JS"
+ "Type:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\n"
+ "deprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005f"
+ "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+ "ogle.protobuf.UninterpretedOption\"/\n\005CTy"
+ "pe\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE"
+ "\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING"
+ "\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"^\n\014OneofOpt"
+ "ions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+ "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
+ "\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow_alias\030\002 \001("
+ "\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uninterp"
+ "reted_option\030\347\007 \003(\0132$.google.protobuf.Un"
+ "interpretedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValu"
+ "eOptions\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024u"
+ "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+ "obuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016S"
+ "erviceOptions\022\031\n\ndeprecated\030! \001(\010:\005false"
+ "\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.google"
+ ".protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002"
+ "\"z\n\rMethodOptions\022\031\n\ndeprecated\030! \001(\010:\005f"
"alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
"ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
- "\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001"
- " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
- "(\0132$.google.protobuf.UninterpretedOption"
- "*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepreca"
- "ted\030! \001(\010:\005false\022C\n\024uninterpreted_option"
- "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO"
- "ption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndep"
- "recated\030! \001(\010:\005false\022C\n\024uninterpreted_op"
- "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
- "tedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOp"
- "tion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uni"
- "nterpretedOption.NamePart\022\030\n\020identifier_"
- "value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022"
- "\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_va"
- "lue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggre"
- "gate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_par"
- "t\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016Source"
- "CodeInfo\022:\n\010location\030\001 \003(\0132(.google.prot"
- "obuf.SourceCodeInfo.Location\032\206\001\n\010Locatio"
- "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n"
- "\020leading_comments\030\003 \001(\t\022\031\n\021trailing_comm"
- "ents\030\004 \001(\t\022!\n\031leading_detached_comments\030"
- "\006 \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotatio"
- "n\030\001 \003(\0132-.google.protobuf.GeneratedCodeI"
- "nfo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003"
- "(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001"
- "(\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020"
- "DescriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032G"
- "oogle.Protobuf.Reflection", 5145);
+ "\200\200\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003"
+ "(\0132-.google.protobuf.UninterpretedOption"
+ ".NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022p"
+ "ositive_int_value\030\004 \001(\004\022\032\n\022negative_int_"
+ "value\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014str"
+ "ing_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t"
+ "\0323\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_ex"
+ "tension\030\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010loca"
+ "tion\030\001 \003(\0132(.google.protobuf.SourceCodeI"
+ "nfo.Location\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B"
+ "\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020leading_comment"
+ "s\030\003 \001(\t\022\031\n\021trailing_comments\030\004 \001(\t\022!\n\031le"
+ "ading_detached_comments\030\006 \003(\t\"\247\001\n\021Genera"
+ "tedCodeInfo\022A\n\nannotation\030\001 \003(\0132-.google"
+ ".protobuf.GeneratedCodeInfo.Annotation\032O"
+ "\n\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source"
+ "_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B"
+ "X\n\023com.google.protobufB\020DescriptorProtos"
+ "H\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf.R"
+ "eflection", 5289);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -826,6 +853,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
FileOptions::default_instance_ = new FileOptions();
MessageOptions::default_instance_ = new MessageOptions();
FieldOptions::default_instance_ = new FieldOptions();
+ OneofOptions::default_instance_ = new OneofOptions();
EnumOptions::default_instance_ = new EnumOptions();
EnumValueOptions::default_instance_ = new EnumValueOptions();
ServiceOptions::default_instance_ = new ServiceOptions();
@@ -850,6 +878,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
FileOptions::default_instance_->InitAsDefaultInstance();
MessageOptions::default_instance_->InitAsDefaultInstance();
FieldOptions::default_instance_->InitAsDefaultInstance();
+ OneofOptions::default_instance_->InitAsDefaultInstance();
EnumOptions::default_instance_->InitAsDefaultInstance();
EnumValueOptions::default_instance_->InitAsDefaultInstance();
ServiceOptions::default_instance_->InitAsDefaultInstance();
@@ -1016,14 +1045,14 @@ void FileDescriptorSet::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorSet)
}
-::google::protobuf::uint8* FileDescriptorSet::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileDescriptorSet::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
// repeated .google.protobuf.FileDescriptorProto file = 1;
for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 1, this->file(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 1, this->file(i), false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -1604,8 +1633,8 @@ void FileDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorProto)
}
-::google::protobuf::uint8* FileDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -1642,43 +1671,43 @@ void FileDescriptorProto::SerializeWithCachedSizes(
// repeated .google.protobuf.DescriptorProto message_type = 4;
for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 4, this->message_type(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 4, this->message_type(i), false, target);
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 5, this->enum_type(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 5, this->enum_type(i), false, target);
}
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 6, this->service(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 6, this->service(i), false, target);
}
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 7, this->extension(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 7, this->extension(i), false, target);
}
// optional .google.protobuf.FileOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 8, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 8, *this->options_, false, target);
}
// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
if (has_source_code_info()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 9, *this->source_code_info_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 9, *this->source_code_info_, false, target);
}
// repeated int32 public_dependency = 10;
@@ -2599,8 +2628,8 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ExtensionRange)
}
-::google::protobuf::uint8* DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto_ExtensionRange::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
// optional int32 start = 1;
if (has_start()) {
@@ -2898,8 +2927,8 @@ void DescriptorProto_ReservedRange::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange)
}
-::google::protobuf::uint8* DescriptorProto_ReservedRange::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto_ReservedRange::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
// optional int32 start = 1;
if (has_start()) {
@@ -3395,8 +3424,8 @@ void DescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto)
}
-::google::protobuf::uint8* DescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -3412,57 +3441,57 @@ void DescriptorProto::SerializeWithCachedSizes(
// repeated .google.protobuf.FieldDescriptorProto field = 2;
for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->field(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->field(i), false, target);
}
// repeated .google.protobuf.DescriptorProto nested_type = 3;
for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, this->nested_type(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, this->nested_type(i), false, target);
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 4, this->enum_type(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 4, this->enum_type(i), false, target);
}
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 5, this->extension_range(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 5, this->extension_range(i), false, target);
}
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 6, this->extension(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 6, this->extension(i), false, target);
}
// optional .google.protobuf.MessageOptions options = 7;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 7, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 7, *this->options_, false, target);
}
// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 8, this->oneof_decl(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 8, this->oneof_decl(i), false, target);
}
// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 9, this->reserved_range(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 9, this->reserved_range(i), false, target);
}
// repeated string reserved_name = 10;
@@ -3637,6 +3666,7 @@ bool DescriptorProto::IsInitialized() const {
if (!::google::protobuf::internal::AllAreInitialized(this->extension())) return false;
if (!::google::protobuf::internal::AllAreInitialized(this->nested_type())) return false;
if (!::google::protobuf::internal::AllAreInitialized(this->enum_type())) return false;
+ if (!::google::protobuf::internal::AllAreInitialized(this->oneof_decl())) return false;
if (has_options()) {
if (!this->options_->IsInitialized()) return false;
}
@@ -4630,8 +4660,8 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FieldDescriptorProto)
}
-::google::protobuf::uint8* FieldDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -4697,8 +4727,8 @@ void FieldDescriptorProto::SerializeWithCachedSizes(
// optional .google.protobuf.FieldOptions options = 8;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 8, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 8, *this->options_, false, target);
}
// optional int32 oneof_index = 9;
@@ -5345,6 +5375,7 @@ void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOption
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int OneofDescriptorProto::kNameFieldNumber;
+const int OneofDescriptorProto::kOptionsFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
OneofDescriptorProto::OneofDescriptorProto()
@@ -5354,6 +5385,7 @@ OneofDescriptorProto::OneofDescriptorProto()
}
void OneofDescriptorProto::InitAsDefaultInstance() {
+ options_ = const_cast< ::google::protobuf::OneofOptions*>(&::google::protobuf::OneofOptions::default_instance());
}
OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
@@ -5368,6 +5400,7 @@ void OneofDescriptorProto::SharedCtor() {
::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ options_ = NULL;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -5379,6 +5412,7 @@ OneofDescriptorProto::~OneofDescriptorProto() {
void OneofDescriptorProto::SharedDtor() {
name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (this != default_instance_) {
+ delete options_;
}
}
@@ -5409,8 +5443,13 @@ OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena
void OneofDescriptorProto::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto)
- if (has_name()) {
- name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (_has_bits_[0 / 32] & 3u) {
+ if (has_name()) {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ if (has_options()) {
+ if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+ }
}
::memset(_has_bits_, 0, sizeof(_has_bits_));
if (_internal_metadata_.have_unknown_fields()) {
@@ -5440,6 +5479,19 @@ bool OneofDescriptorProto::MergePartialFromCodedStream(
} else {
goto handle_unusual;
}
+ if (input->ExpectTag(18)) goto parse_options;
+ break;
+ }
+
+ // optional .google.protobuf.OneofOptions options = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_options:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_options()));
+ } else {
+ goto handle_unusual;
+ }
if (input->ExpectAtEnd()) goto success;
break;
}
@@ -5479,6 +5531,12 @@ void OneofDescriptorProto::SerializeWithCachedSizes(
1, this->name(), output);
}
+ // optional .google.protobuf.OneofOptions options = 2;
+ if (has_options()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, *this->options_, output);
+ }
+
if (_internal_metadata_.have_unknown_fields()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
@@ -5486,8 +5544,8 @@ void OneofDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.OneofDescriptorProto)
}
-::google::protobuf::uint8* OneofDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* OneofDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -5500,6 +5558,13 @@ void OneofDescriptorProto::SerializeWithCachedSizes(
1, this->name(), target);
}
+ // optional .google.protobuf.OneofOptions options = 2;
+ if (has_options()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ InternalWriteMessageNoVirtualToArray(
+ 2, *this->options_, false, target);
+ }
+
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
@@ -5512,13 +5577,22 @@ int OneofDescriptorProto::ByteSize() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
int total_size = 0;
- // optional string name = 1;
- if (has_name()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::StringSize(
- this->name());
- }
+ if (_has_bits_[0 / 32] & 3u) {
+ // optional string name = 1;
+ if (has_name()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->name());
+ }
+
+ // optional .google.protobuf.OneofOptions options = 2;
+ if (has_options()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *this->options_);
+ }
+ }
if (_internal_metadata_.have_unknown_fields()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5553,6 +5627,9 @@ void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) {
set_has_name();
name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
}
+ if (from.has_options()) {
+ mutable_options()->::google::protobuf::OneofOptions::MergeFrom(from.options());
+ }
}
if (from._internal_metadata_.have_unknown_fields()) {
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
@@ -5575,6 +5652,9 @@ void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) {
bool OneofDescriptorProto::IsInitialized() const {
+ if (has_options()) {
+ if (!this->options_->IsInitialized()) return false;
+ }
return true;
}
@@ -5584,6 +5664,7 @@ void OneofDescriptorProto::Swap(OneofDescriptorProto* other) {
}
void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
name_.Swap(&other->name_);
+ std::swap(options_, other->options_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_internal_metadata_.Swap(&other->_internal_metadata_);
std::swap(_cached_size_, other->_cached_size_);
@@ -5654,6 +5735,50 @@ void OneofDescriptorProto::clear_name() {
// @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
}
+// optional .google.protobuf.OneofOptions options = 2;
+bool OneofDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void OneofDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000002u;
+}
+void OneofDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+void OneofDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+ clear_has_options();
+}
+const ::google::protobuf::OneofOptions& OneofDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::OneofOptions* OneofDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::OneofOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+ return options_;
+}
+::google::protobuf::OneofOptions* OneofDescriptorProto::release_options() {
+ // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+ clear_has_options();
+ ::google::protobuf::OneofOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+void OneofDescriptorProto::set_allocated_options(::google::protobuf::OneofOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
// ===================================================================
@@ -5854,8 +5979,8 @@ void EnumDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.EnumDescriptorProto)
}
-::google::protobuf::uint8* EnumDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -5871,15 +5996,15 @@ void EnumDescriptorProto::SerializeWithCachedSizes(
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->value(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->value(i), false, target);
}
// optional .google.protobuf.EnumOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, *this->options_, false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -6335,8 +6460,8 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueDescriptorProto)
}
-::google::protobuf::uint8* EnumValueDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValueDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -6357,8 +6482,8 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes(
// optional .google.protobuf.EnumValueOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, *this->options_, false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -6810,8 +6935,8 @@ void ServiceDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.ServiceDescriptorProto)
}
-::google::protobuf::uint8* ServiceDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ServiceDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -6827,15 +6952,15 @@ void ServiceDescriptorProto::SerializeWithCachedSizes(
// repeated .google.protobuf.MethodDescriptorProto method = 2;
for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->method(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->method(i), false, target);
}
// optional .google.protobuf.ServiceOptions options = 3;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, *this->options_, false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -7399,8 +7524,8 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.MethodDescriptorProto)
}
-::google::protobuf::uint8* MethodDescriptorProto::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MethodDescriptorProto::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
// optional string name = 1;
if (has_name()) {
@@ -7438,8 +7563,8 @@ void MethodDescriptorProto::SerializeWithCachedSizes(
// optional .google.protobuf.MethodOptions options = 4;
if (has_options()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 4, *this->options_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 4, *this->options_, false, target);
}
// optional bool client_streaming = 5 [default = false];
@@ -8432,8 +8557,8 @@ void FileOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FileOptions)
}
-::google::protobuf::uint8* FileOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
// optional string java_package = 1;
if (has_java_package()) {
@@ -8539,13 +8664,13 @@ void FileOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -9573,8 +9698,8 @@ void MessageOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.MessageOptions)
}
-::google::protobuf::uint8* MessageOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
// optional bool message_set_wire_format = 1 [default = false];
if (has_message_set_wire_format()) {
@@ -9599,13 +9724,13 @@ void MessageOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -10237,8 +10362,8 @@ void FieldOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FieldOptions)
}
-::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
if (has_ctype()) {
@@ -10275,13 +10400,13 @@ void FieldOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -10626,6 +10751,300 @@ FieldOptions::uninterpreted_option() const {
// ===================================================================
#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OneofOptions::kUninterpretedOptionFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OneofOptions::OneofOptions()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:google.protobuf.OneofOptions)
+}
+
+void OneofOptions::InitAsDefaultInstance() {
+}
+
+OneofOptions::OneofOptions(const OneofOptions& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofOptions)
+}
+
+void OneofOptions::SharedCtor() {
+ _cached_size_ = 0;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+OneofOptions::~OneofOptions() {
+ // @@protoc_insertion_point(destructor:google.protobuf.OneofOptions)
+ SharedDtor();
+}
+
+void OneofOptions::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void OneofOptions::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OneofOptions::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return OneofOptions_descriptor_;
+}
+
+const OneofOptions& OneofOptions::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ return *default_instance_;
+}
+
+OneofOptions* OneofOptions::default_instance_ = NULL;
+
+OneofOptions* OneofOptions::New(::google::protobuf::Arena* arena) const {
+ OneofOptions* n = new OneofOptions;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void OneofOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofOptions)
+ _extensions_.Clear();
+ uninterpreted_option_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ if (_internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->Clear();
+ }
+}
+
+bool OneofOptions::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:google.protobuf.OneofOptions)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ case 999: {
+ if (tag == 7994) {
+ DO_(input->IncrementRecursionDepth());
+ parse_loop_uninterpreted_option:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+ input, add_uninterpreted_option()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+ input->UnsafeDecrementRecursionDepth();
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ if ((8000u <= tag)) {
+ DO_(_extensions_.ParseField(tag, input, default_instance_,
+ mutable_unknown_fields()));
+ continue;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:google.protobuf.OneofOptions)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:google.protobuf.OneofOptions)
+ return false;
+#undef DO_
+}
+
+void OneofOptions::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:google.protobuf.OneofOptions)
+ // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 999, this->uninterpreted_option(i), output);
+ }
+
+ // Extension range [1000, 536870912)
+ _extensions_.SerializeWithCachedSizes(
+ 1000, 536870912, output);
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:google.protobuf.OneofOptions)
+}
+
+::google::protobuf::uint8* OneofOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions)
+ // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
+ }
+
+ // Extension range [1000, 536870912)
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
+ return target;
+}
+
+int OneofOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions)
+ int total_size = 0;
+
+ // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->uninterpreted_option(i));
+ }
+
+ total_size += _extensions_.ByteSize();
+
+ if (_internal_metadata_.have_unknown_fields()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void OneofOptions::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofOptions)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const OneofOptions* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const OneofOptions>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.OneofOptions)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.OneofOptions)
+ MergeFrom(*source);
+ }
+}
+
+void OneofOptions::MergeFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+ _extensions_.MergeFrom(from._extensions_);
+ if (from._internal_metadata_.have_unknown_fields()) {
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+ }
+}
+
+void OneofOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.OneofOptions)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void OneofOptions::CopyFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofOptions)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool OneofOptions::IsInitialized() const {
+
+ if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
+ if (!_extensions_.IsInitialized()) return false; return true;
+}
+
+void OneofOptions::Swap(OneofOptions* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void OneofOptions::InternalSwap(OneofOptions* other) {
+ uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+ _extensions_.Swap(&other->_extensions_);
+}
+
+::google::protobuf::Metadata OneofOptions::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = OneofOptions_descriptor_;
+ metadata.reflection = OneofOptions_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int OneofOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+void OneofOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int EnumOptions::kAllowAliasFieldNumber;
const int EnumOptions::kDeprecatedFieldNumber;
const int EnumOptions::kUninterpretedOptionFieldNumber;
@@ -10834,8 +11253,8 @@ void EnumOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.EnumOptions)
}
-::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
// optional bool allow_alias = 2;
if (has_allow_alias()) {
@@ -10850,13 +11269,13 @@ void EnumOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11231,8 +11650,8 @@ void EnumValueOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueOptions)
}
-::google::protobuf::uint8* EnumValueOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValueOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
// optional bool deprecated = 1 [default = false];
if (has_deprecated()) {
@@ -11242,13 +11661,13 @@ void EnumValueOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11588,8 +12007,8 @@ void ServiceOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.ServiceOptions)
}
-::google::protobuf::uint8* ServiceOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ServiceOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
// optional bool deprecated = 33 [default = false];
if (has_deprecated()) {
@@ -11599,13 +12018,13 @@ void ServiceOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11945,8 +12364,8 @@ void MethodOptions::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.MethodOptions)
}
-::google::protobuf::uint8* MethodOptions::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MethodOptions::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
// optional bool deprecated = 33 [default = false];
if (has_deprecated()) {
@@ -11956,13 +12375,13 @@ void MethodOptions::SerializeWithCachedSizes(
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 999, this->uninterpreted_option(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 999, this->uninterpreted_option(i), false, target);
}
// Extension range [1000, 536870912)
- target = _extensions_.SerializeWithCachedSizesToArray(
- 1000, 536870912, target);
+ target = _extensions_.InternalSerializeWithCachedSizesToArray(
+ 1000, 536870912, false, target);
if (_internal_metadata_.have_unknown_fields()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -12303,8 +12722,8 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption.NamePart)
}
-::google::protobuf::uint8* UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UninterpretedOption_NamePart::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
// required string name_part = 1;
if (has_name_part()) {
@@ -12765,14 +13184,14 @@ void UninterpretedOption::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption)
}
-::google::protobuf::uint8* UninterpretedOption::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UninterpretedOption::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->name(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->name(i), false, target);
}
// optional string identifier_value = 3;
@@ -13606,8 +14025,8 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo.Location)
}
-::google::protobuf::uint8* SourceCodeInfo_Location::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceCodeInfo_Location::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
// repeated int32 path = 1 [packed = true];
if (this->path_size() > 0) {
@@ -13964,14 +14383,14 @@ void SourceCodeInfo::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo)
}
-::google::protobuf::uint8* SourceCodeInfo::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceCodeInfo::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 1, this->location(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 1, this->location(i), false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
@@ -14571,8 +14990,8 @@ void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation)
}
-::google::protobuf::uint8* GeneratedCodeInfo_Annotation::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* GeneratedCodeInfo_Annotation::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
// repeated int32 path = 1 [packed = true];
if (this->path_size() > 0) {
@@ -14886,14 +15305,14 @@ void GeneratedCodeInfo::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo)
}
-::google::protobuf::uint8* GeneratedCodeInfo::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* GeneratedCodeInfo::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 1, this->annotation(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 1, this->annotation(i), false, target);
}
if (_internal_metadata_.have_unknown_fields()) {
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 92a0a3a7..5a9e12bc 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -56,6 +56,7 @@ class MessageOptions;
class MethodDescriptorProto;
class MethodOptions;
class OneofDescriptorProto;
+class OneofOptions;
class ServiceDescriptorProto;
class ServiceOptions;
class SourceCodeInfo;
@@ -180,7 +181,7 @@ inline bool FieldOptions_JSType_Parse(
}
// ===================================================================
-class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorSet) */ {
public:
FileDescriptorSet();
virtual ~FileDescriptorSet();
@@ -222,7 +223,11 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -272,7 +277,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorProto) */ {
public:
FileDescriptorProto();
virtual ~FileDescriptorProto();
@@ -314,7 +319,11 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -515,7 +524,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ExtensionRange) */ {
public:
DescriptorProto_ExtensionRange();
virtual ~DescriptorProto_ExtensionRange();
@@ -557,7 +566,11 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -614,7 +627,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ReservedRange) */ {
public:
DescriptorProto_ReservedRange();
virtual ~DescriptorProto_ReservedRange();
@@ -656,7 +669,11 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protob
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -713,7 +730,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protob
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto) */ {
public:
DescriptorProto();
virtual ~DescriptorProto();
@@ -755,7 +772,11 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -930,7 +951,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldDescriptorProto) */ {
public:
FieldDescriptorProto();
virtual ~FieldDescriptorProto();
@@ -972,7 +993,11 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1222,7 +1247,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofDescriptorProto) */ {
public:
OneofDescriptorProto();
virtual ~OneofDescriptorProto();
@@ -1264,7 +1289,11 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1298,15 +1327,27 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa
::std::string* release_name();
void set_allocated_name(::std::string* name);
+ // optional .google.protobuf.OneofOptions options = 2;
+ bool has_options() const;
+ void clear_options();
+ static const int kOptionsFieldNumber = 2;
+ const ::google::protobuf::OneofOptions& options() const;
+ ::google::protobuf::OneofOptions* mutable_options();
+ ::google::protobuf::OneofOptions* release_options();
+ void set_allocated_options(::google::protobuf::OneofOptions* options);
+
// @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
private:
inline void set_has_name();
inline void clear_has_name();
+ inline void set_has_options();
+ inline void clear_has_options();
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
::google::protobuf::internal::ArenaStringPtr name_;
+ ::google::protobuf::OneofOptions* options_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1316,7 +1357,7 @@ class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Messa
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto) */ {
public:
EnumDescriptorProto();
virtual ~EnumDescriptorProto();
@@ -1358,7 +1399,11 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1435,7 +1480,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueDescriptorProto) */ {
public:
EnumValueDescriptorProto();
virtual ~EnumValueDescriptorProto();
@@ -1477,7 +1522,11 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1551,7 +1600,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceDescriptorProto) */ {
public:
ServiceDescriptorProto();
virtual ~ServiceDescriptorProto();
@@ -1593,7 +1642,11 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1670,7 +1723,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodDescriptorProto) */ {
public:
MethodDescriptorProto();
virtual ~MethodDescriptorProto();
@@ -1712,7 +1765,11 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -1826,7 +1883,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileOptions) */ {
public:
FileOptions();
virtual ~FileOptions();
@@ -1868,7 +1925,11 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2114,7 +2175,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MessageOptions) */ {
public:
MessageOptions();
virtual ~MessageOptions();
@@ -2156,7 +2217,11 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2249,7 +2314,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldOptions) */ {
public:
FieldOptions();
virtual ~FieldOptions();
@@ -2291,7 +2356,11 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2460,7 +2529,106 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT OneofOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofOptions) */ {
+ public:
+ OneofOptions();
+ virtual ~OneofOptions();
+
+ OneofOptions(const OneofOptions& from);
+
+ inline OneofOptions& operator=(const OneofOptions& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields();
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields();
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const OneofOptions& default_instance();
+
+ void Swap(OneofOptions* other);
+
+ // implements Message ----------------------------------------------
+
+ inline OneofOptions* New() const { return New(NULL); }
+
+ OneofOptions* New(::google::protobuf::Arena* arena) const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const OneofOptions& from);
+ void MergeFrom(const OneofOptions& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ void InternalSwap(OneofOptions* other);
+ private:
+ inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+ return _internal_metadata_.arena();
+ }
+ inline void* MaybeArenaPtr() const {
+ return _internal_metadata_.raw_arena_ptr();
+ }
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+ int uninterpreted_option_size() const;
+ void clear_uninterpreted_option();
+ static const int kUninterpretedOptionFieldNumber = 999;
+ const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+ ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+ ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ mutable_uninterpreted_option();
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ uninterpreted_option() const;
+
+ GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(OneofOptions)
+ // @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
+ private:
+
+ ::google::protobuf::internal::ExtensionSet _extensions_;
+
+ ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+ friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+ friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+ void InitAsDefaultInstance();
+ static OneofOptions* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumOptions) */ {
public:
EnumOptions();
virtual ~EnumOptions();
@@ -2502,7 +2670,11 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2575,7 +2747,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueOptions) */ {
public:
EnumValueOptions();
virtual ~EnumValueOptions();
@@ -2617,7 +2789,11 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2680,7 +2856,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceOptions) */ {
public:
ServiceOptions();
virtual ~ServiceOptions();
@@ -2722,7 +2898,11 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2785,7 +2965,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodOptions) */ {
public:
MethodOptions();
virtual ~MethodOptions();
@@ -2827,7 +3007,11 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2890,7 +3074,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption.NamePart) */ {
public:
UninterpretedOption_NamePart();
virtual ~UninterpretedOption_NamePart();
@@ -2932,7 +3116,11 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -2997,7 +3185,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption) */ {
public:
UninterpretedOption();
virtual ~UninterpretedOption();
@@ -3039,7 +3227,11 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -3166,7 +3358,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo.Location) */ {
public:
SourceCodeInfo_Location();
virtual ~SourceCodeInfo_Location();
@@ -3208,7 +3400,11 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -3320,7 +3516,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Me
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo) */ {
public:
SourceCodeInfo();
virtual ~SourceCodeInfo();
@@ -3362,7 +3558,11 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -3414,7 +3614,7 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo.Annotation) */ {
public:
GeneratedCodeInfo_Annotation();
virtual ~GeneratedCodeInfo_Annotation();
@@ -3456,7 +3656,11 @@ class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobu
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -3542,7 +3746,7 @@ class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobu
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo) */ {
public:
GeneratedCodeInfo();
virtual ~GeneratedCodeInfo();
@@ -3584,7 +3788,11 @@ class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -5106,6 +5314,50 @@ inline void OneofDescriptorProto::set_allocated_name(::std::string* name) {
// @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
}
+// optional .google.protobuf.OneofOptions options = 2;
+inline bool OneofDescriptorProto::has_options() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void OneofDescriptorProto::set_has_options() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void OneofDescriptorProto::clear_has_options() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void OneofDescriptorProto::clear_options() {
+ if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+ clear_has_options();
+}
+inline const ::google::protobuf::OneofOptions& OneofDescriptorProto::options() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+ return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+inline ::google::protobuf::OneofOptions* OneofDescriptorProto::mutable_options() {
+ set_has_options();
+ if (options_ == NULL) {
+ options_ = new ::google::protobuf::OneofOptions;
+ }
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+ return options_;
+}
+inline ::google::protobuf::OneofOptions* OneofDescriptorProto::release_options() {
+ // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+ clear_has_options();
+ ::google::protobuf::OneofOptions* temp = options_;
+ options_ = NULL;
+ return temp;
+}
+inline void OneofDescriptorProto::set_allocated_options(::google::protobuf::OneofOptions* options) {
+ delete options_;
+ options_ = options;
+ if (options) {
+ set_has_options();
+ } else {
+ clear_has_options();
+ }
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
// -------------------------------------------------------------------
// EnumDescriptorProto
@@ -6587,6 +6839,40 @@ FieldOptions::uninterpreted_option() const {
// -------------------------------------------------------------------
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int OneofOptions::uninterpreted_option_size() const {
+ return uninterpreted_option_.size();
+}
+inline void OneofOptions::clear_uninterpreted_option() {
+ uninterpreted_option_.Clear();
+}
+inline const ::google::protobuf::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+ // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Get(index);
+}
+inline ::google::protobuf::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+ // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Mutable(index);
+}
+inline ::google::protobuf::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+ // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+ // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+ return &uninterpreted_option_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+ // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+ return uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
// EnumOptions
// optional bool allow_alias = 2;
@@ -7669,6 +7955,8 @@ GeneratedCodeInfo::annotation() const {
// -------------------------------------------------------------------
+// -------------------------------------------------------------------
+
// @@protoc_insertion_point(namespace_scope)
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 08b15554..da853dbc 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -202,6 +202,7 @@ message FieldDescriptorProto {
// Describes a oneof.
message OneofDescriptorProto {
optional string name = 1;
+ optional OneofOptions options = 2;
}
// Describes an enum type.
@@ -538,6 +539,14 @@ message FieldOptions {
extensions 1000 to max;
}
+message OneofOptions {
+ // 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 true to allow mapping different tag names to the same
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index 1fc3816e..4f568f7d 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -48,7 +48,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index f937b9ea..4183138f 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -55,7 +55,6 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -2705,6 +2704,7 @@ TEST(CustomOptions, OptionLocations) {
protobuf_unittest::TestMessageWithCustomOptions::descriptor();
const FileDescriptor* file = message->file();
const FieldDescriptor* field = message->FindFieldByName("field1");
+ const OneofDescriptor* oneof = message->FindOneofByName("AnOneof");
const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
// TODO(benjy): Support EnumValue options, once the compiler does.
const ServiceDescriptor* service =
@@ -2719,6 +2719,8 @@ TEST(CustomOptions, OptionLocations) {
field->options().GetExtension(protobuf_unittest::field_opt1));
EXPECT_EQ(42, // Check that we get the default for an option we don't set.
field->options().GetExtension(protobuf_unittest::field_opt2));
+ EXPECT_EQ(-99,
+ oneof->options().GetExtension(protobuf_unittest::oneof_opt1));
EXPECT_EQ(-789,
enm->options().GetExtension(protobuf_unittest::enum_opt1));
EXPECT_EQ(123,
@@ -5027,7 +5029,7 @@ TEST_F(ValidationErrorTest, AggregateValueParseError) {
BuildFileWithErrors(
EmbedAggregateValue("aggregate_value: \"1+2\""),
"foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
- "value for \"foo\": Expected identifier.\n");
+ "value for \"foo\": Expected identifier, got: 1\n");
}
TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
@@ -5834,7 +5836,7 @@ TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
" field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
" field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
"}",
- "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" "
+ "foo.proto: Foo: OTHER: The JSON camel-case name of field \"Name\" "
"conflicts with field \"name\". This is not allowed in proto3.\n");
// Underscores are ignored.
BuildFileWithErrors(
@@ -5845,7 +5847,7 @@ TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
" field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
" field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
"}",
- "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" "
+ "foo.proto: Foo: OTHER: The JSON camel-case name of field \"_a__b_\" "
"conflicts with field \"ab\". This is not allowed in proto3.\n");
}
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index e3639346..b0c641bf 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -279,8 +279,8 @@ void Duration::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Duration)
}
-::google::protobuf::uint8* Duration::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Duration::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
// optional int64 seconds = 1;
if (this->seconds() != 0) {
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 215a52c4..ad479639 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -41,7 +41,7 @@ class Duration;
// ===================================================================
-class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Duration) */ {
public:
Duration();
virtual ~Duration();
@@ -75,7 +75,11 @@ class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 9e83bd29..5d914bf6 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -70,7 +70,6 @@
#endif
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/descriptor.h>
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 70e437d7..fe51d8cf 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -45,8 +45,6 @@
#include <google/protobuf/stubs/shared_ptr.h>
#endif
-#include <google/protobuf/stubs/scoped_ptr.h>
-#include <google/protobuf/stubs/common.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
@@ -55,6 +53,7 @@
#include <google/protobuf/unittest_no_field_presence.pb.h>
#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index dcf84263..8b461201 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -221,8 +221,8 @@ void Empty::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Empty)
}
-::google::protobuf::uint8* Empty::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Empty::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
return target;
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 868009fc..8e78733b 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -41,7 +41,7 @@ class Empty;
// ===================================================================
-class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
public:
Empty();
virtual ~Empty();
@@ -80,7 +80,11 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 9afb2361..7d20a0f8 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -177,7 +177,8 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* containing_type,
// ===================================================================
// Constructors and basic methods.
-ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena) : arena_(arena) {
+ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena)
+ : arena_(arena) {
if (arena_ != NULL) {
arena_->OwnDestructor(&extensions_);
}
@@ -188,7 +189,7 @@ ExtensionSet::ExtensionSet() : arena_(NULL) {}
ExtensionSet::~ExtensionSet() {
// Deletes all allocated extensions.
if (arena_ == NULL) {
- for (map<int, Extension>::iterator iter = extensions_.begin();
+ for (ExtensionMap::iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
iter->second.Free();
}
@@ -201,7 +202,7 @@ ExtensionSet::~ExtensionSet() {
// vector<const FieldDescriptor*>* output) const
bool ExtensionSet::Has(int number) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) return false;
GOOGLE_DCHECK(!iter->second.is_repeated);
return !iter->second.is_cleared;
@@ -209,7 +210,7 @@ bool ExtensionSet::Has(int number) const {
int ExtensionSet::NumExtensions() const {
int result = 0;
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
if (!iter->second.is_cleared) {
++result;
@@ -219,13 +220,13 @@ int ExtensionSet::NumExtensions() const {
}
int ExtensionSet::ExtensionSize(int number) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) return false;
return iter->second.GetSize();
}
FieldType ExtensionSet::ExtensionType(int number) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) {
GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). ";
return 0;
@@ -237,7 +238,7 @@ FieldType ExtensionSet::ExtensionType(int number) const {
}
void ExtensionSet::ClearExtension(int number) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
if (iter == extensions_.end()) return;
iter->second.Clear();
}
@@ -265,7 +266,7 @@ enum Cardinality {
\
LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \
LOWERCASE default_value) const { \
- map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ ExtensionMap::const_iterator iter = extensions_.find(number); \
if (iter == extensions_.end() || iter->second.is_cleared) { \
return default_value; \
} else { \
@@ -290,7 +291,7 @@ void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \
} \
\
LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \
- map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ ExtensionMap::const_iterator iter = extensions_.find(number); \
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \
return iter->second.repeated_##LOWERCASE##_value->Get(index); \
@@ -298,7 +299,7 @@ LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \
\
void ExtensionSet::SetRepeated##CAMELCASE( \
int number, int index, LOWERCASE value) { \
- map<int, Extension>::iterator iter = extensions_.find(number); \
+ ExtensionMap::iterator iter = extensions_.find(number); \
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \
iter->second.repeated_##LOWERCASE##_value->Set(index, value); \
@@ -334,7 +335,7 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
const void* ExtensionSet::GetRawRepeatedField(int number,
const void* default_value) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) {
return default_value;
}
@@ -408,7 +409,7 @@ void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
// Compatible version using old call signature. Does not create extensions when
// the don't already exist; instead, just GOOGLE_CHECK-fails.
void* ExtensionSet::MutableRawRepeatedField(int number) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter == extensions_.end()) << "Extension not found.";
// We assume that all the RepeatedField<>* pointers have the same
// size and alignment within the anonymous union in Extension.
@@ -420,7 +421,7 @@ void* ExtensionSet::MutableRawRepeatedField(int number) {
// Enums
int ExtensionSet::GetEnum(int number, int default_value) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end() || iter->second.is_cleared) {
// Not present. Return the default value.
return default_value;
@@ -445,14 +446,14 @@ void ExtensionSet::SetEnum(int number, FieldType type, int value,
}
int ExtensionSet::GetRepeatedEnum(int number, int index) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM);
return iter->second.repeated_enum_value->Get(index);
}
void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM);
iter->second.repeated_enum_value->Set(index, value);
@@ -481,7 +482,7 @@ void ExtensionSet::AddEnum(int number, FieldType type,
const string& ExtensionSet::GetString(int number,
const string& default_value) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end() || iter->second.is_cleared) {
// Not present. Return the default value.
return default_value;
@@ -507,14 +508,14 @@ string* ExtensionSet::MutableString(int number, FieldType type,
}
const string& ExtensionSet::GetRepeatedString(int number, int index) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING);
return iter->second.repeated_string_value->Get(index);
}
string* ExtensionSet::MutableRepeatedString(int number, int index) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING);
return iter->second.repeated_string_value->Mutable(index);
@@ -541,7 +542,7 @@ string* ExtensionSet::AddString(int number, FieldType type,
const MessageLite& ExtensionSet::GetMessage(
int number, const MessageLite& default_value) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end()) {
// Not present. Return the default value.
return default_value;
@@ -664,7 +665,7 @@ void ExtensionSet::UnsafeArenaSetAllocatedMessage(
MessageLite* ExtensionSet::ReleaseMessage(int number,
const MessageLite& prototype) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
if (iter == extensions_.end()) {
// Not present. Return NULL.
return NULL;
@@ -693,7 +694,7 @@ MessageLite* ExtensionSet::ReleaseMessage(int number,
MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
int number, const MessageLite& prototype) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
if (iter == extensions_.end()) {
// Not present. Return NULL.
return NULL;
@@ -720,14 +721,14 @@ MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
const MessageLite& ExtensionSet::GetRepeatedMessage(
int number, int index) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE);
return iter->second.repeated_message_value->Get(index);
}
MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE);
return iter->second.repeated_message_value->Mutable(index);
@@ -766,7 +767,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
#undef GOOGLE_DCHECK_TYPE
void ExtensionSet::RemoveLast(int number) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
Extension* extension = &iter->second;
@@ -807,7 +808,7 @@ void ExtensionSet::RemoveLast(int number) {
}
MessageLite* ExtensionSet::ReleaseLast(int number) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
Extension* extension = &iter->second;
@@ -817,7 +818,7 @@ MessageLite* ExtensionSet::ReleaseLast(int number) {
}
void ExtensionSet::SwapElements(int number, int index1, int index2) {
- map<int, Extension>::iterator iter = extensions_.find(number);
+ ExtensionMap::iterator iter = extensions_.find(number);
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
Extension* extension = &iter->second;
@@ -860,14 +861,14 @@ void ExtensionSet::SwapElements(int number, int index1, int index2) {
// ===================================================================
void ExtensionSet::Clear() {
- for (map<int, Extension>::iterator iter = extensions_.begin();
+ for (ExtensionMap::iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
iter->second.Clear();
}
}
void ExtensionSet::MergeFrom(const ExtensionSet& other) {
- for (map<int, Extension>::const_iterator iter = other.extensions_.begin();
+ for (ExtensionMap::const_iterator iter = other.extensions_.begin();
iter != other.extensions_.end(); ++iter) {
const Extension& other_extension = iter->second;
InternalExtensionMergeFrom(iter->first, other_extension);
@@ -1031,8 +1032,8 @@ void ExtensionSet::Swap(ExtensionSet* x) {
void ExtensionSet::SwapExtension(ExtensionSet* other,
int number) {
if (this == other) return;
- map<int, Extension>::iterator this_iter = extensions_.find(number);
- map<int, Extension>::iterator other_iter = other->extensions_.find(number);
+ ExtensionMap::iterator this_iter = extensions_.find(number);
+ ExtensionMap::iterator other_iter = other->extensions_.find(number);
if (this_iter == extensions_.end() &&
other_iter == other->extensions_.end()) {
@@ -1052,7 +1053,7 @@ void ExtensionSet::SwapExtension(ExtensionSet* other,
// implemented in ExtensionSet's MergeFrom.
ExtensionSet temp;
temp.InternalExtensionMergeFrom(number, other_iter->second);
- map<int, Extension>::iterator temp_iter = temp.extensions_.find(number);
+ ExtensionMap::iterator temp_iter = temp.extensions_.find(number);
other_iter->second.Clear();
other->InternalExtensionMergeFrom(number, this_iter->second);
this_iter->second.Clear();
@@ -1085,7 +1086,7 @@ void ExtensionSet::SwapExtension(ExtensionSet* other,
bool ExtensionSet::IsInitialized() const {
// Extensions are never required. However, we need to check that all
// embedded messages are initialized.
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
const Extension& extension = iter->second;
if (cpp_type(extension.type) == WireFormatLite::CPPTYPE_MESSAGE) {
@@ -1345,7 +1346,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
void ExtensionSet::SerializeWithCachedSizes(
int start_field_number, int end_field_number,
io::CodedOutputStream* output) const {
- map<int, Extension>::const_iterator iter;
+ ExtensionMap::const_iterator iter;
for (iter = extensions_.lower_bound(start_field_number);
iter != extensions_.end() && iter->first < end_field_number;
++iter) {
@@ -1356,7 +1357,7 @@ void ExtensionSet::SerializeWithCachedSizes(
int ExtensionSet::ByteSize() const {
int total_size = 0;
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
total_size += iter->second.ByteSize(iter->first);
}
@@ -1370,7 +1371,7 @@ int ExtensionSet::ByteSize() const {
bool ExtensionSet::MaybeNewExtension(int number,
const FieldDescriptor* descriptor,
Extension** result) {
- pair<map<int, Extension>::iterator, bool> insert_result =
+ pair<ExtensionMap::iterator, bool> insert_result =
extensions_.insert(std::make_pair(number, Extension()));
*result = &insert_result.first->second;
(*result)->descriptor = descriptor;
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index bca179be..a92c5043 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -273,6 +273,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
MessageLite* ReleaseMessage(const FieldDescriptor* descriptor,
MessageFactory* factory);
+ MessageLite* UnsafeArenaReleaseMessage(const FieldDescriptor* descriptor,
+ MessageFactory* factory);
#undef desc
::google::protobuf::Arena* GetArenaNoVirtual() const { return arena_; }
@@ -403,13 +405,27 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// serialized extensions.
//
// Returns a pointer past the last written byte.
- uint8* SerializeWithCachedSizesToArray(int start_field_number,
- int end_field_number,
- uint8* target) const;
+ uint8* InternalSerializeWithCachedSizesToArray(int start_field_number,
+ int end_field_number,
+ bool deterministic,
+ uint8* target) const;
// Like above but serializes in MessageSet format.
void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
- uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
+ uint8* InternalSerializeMessageSetWithCachedSizesToArray(bool deterministic,
+ uint8* target) const;
+
+ // For backward-compatibility, versions of two of the above methods that
+ // are never forced to serialize deterministically.
+ uint8* SerializeWithCachedSizesToArray(int start_field_number,
+ int end_field_number,
+ uint8* target) const {
+ return InternalSerializeWithCachedSizesToArray(
+ start_field_number, end_field_number, false, target);
+ }
+ uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const {
+ return InternalSerializeMessageSetWithCachedSizesToArray(false, target);
+ }
// Returns the total serialized size of all the extensions.
int ByteSize() const;
@@ -456,6 +472,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
virtual void WriteMessage(int number,
io::CodedOutputStream* output) const = 0;
virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
+ virtual uint8* InternalWriteMessageToArray(int number, bool,
+ uint8* target) const {
+ // TODO(gpike): make this pure virtual. This is a placeholder because we
+ // need to update third_party/upb, for example.
+ return WriteMessageToArray(number, target);
+ }
+
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
};
@@ -522,14 +545,16 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void SerializeFieldWithCachedSizes(
int number,
io::CodedOutputStream* output) const;
- uint8* SerializeFieldWithCachedSizesToArray(
+ uint8* InternalSerializeFieldWithCachedSizesToArray(
int number,
+ bool deterministic,
uint8* target) const;
void SerializeMessageSetItemWithCachedSizes(
int number,
io::CodedOutputStream* output) const;
- uint8* SerializeMessageSetItemWithCachedSizesToArray(
+ uint8* InternalSerializeMessageSetItemWithCachedSizesToArray(
int number,
+ bool deterministic,
uint8* target) const;
int ByteSize(int number) const;
int MessageSetItemByteSize(int number) const;
@@ -538,6 +563,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void Free();
int SpaceUsedExcludingSelf() const;
};
+ typedef std::map<int, Extension> ExtensionMap;
// Merges existing Extension from other_extension
@@ -608,7 +634,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// only contain a small number of extensions whereas hash_map is optimized
// for 100 elements or more. Also, we want AppendToList() to order fields
// by field number.
- std::map<int, Extension> extensions_;
+ ExtensionMap extensions_;
::google::protobuf::Arena* arena_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
};
@@ -980,11 +1006,22 @@ class MessageTypeTraits {
MutableType message, ExtensionSet* set) {
set->SetAllocatedMessage(number, field_type, NULL, message);
}
+ static inline void UnsafeArenaSetAllocated(int number, FieldType field_type,
+ MutableType message,
+ ExtensionSet* set) {
+ set->UnsafeArenaSetAllocatedMessage(number, field_type, NULL, message);
+ }
static inline MutableType Release(int number, FieldType /* field_type */,
ExtensionSet* set) {
return static_cast<Type*>(set->ReleaseMessage(
number, Type::default_instance()));
}
+ static inline MutableType UnsafeArenaRelease(int number,
+ FieldType /* field_type */,
+ ExtensionSet* set) {
+ return static_cast<Type*>(set->UnsafeArenaReleaseMessage(
+ number, Type::default_instance()));
+ }
};
// forward declaration
@@ -1178,12 +1215,32 @@ class ExtensionIdentifier {
template <typename _proto_TypeTraits, \
::google::protobuf::internal::FieldType _field_type, \
bool _is_packed> \
+ inline void UnsafeArenaSetAllocatedExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
+ typename _proto_TypeTraits::Singular::MutableType value) { \
+ _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, \
+ value, &_extensions_); \
+ } \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
inline typename _proto_TypeTraits::Singular::MutableType ReleaseExtension( \
const ::google::protobuf::internal::ExtensionIdentifier< \
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
return _proto_TypeTraits::Release(id.number(), _field_type, \
&_extensions_); \
} \
+ template <typename _proto_TypeTraits, \
+ ::google::protobuf::internal::FieldType _field_type, \
+ bool _is_packed> \
+ inline typename _proto_TypeTraits::Singular::MutableType \
+ UnsafeArenaReleaseExtension( \
+ const ::google::protobuf::internal::ExtensionIdentifier< \
+ CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
+ return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, \
+ &_extensions_); \
+ } \
\
/* Repeated accessors */ \
template <typename _proto_TypeTraits, \
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 82e3e099..7177d786 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -95,7 +95,7 @@ void ExtensionSet::AppendToList(
const Descriptor* containing_type,
const DescriptorPool* pool,
std::vector<const FieldDescriptor*>* output) const {
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
bool has = false;
if (iter->second.is_repeated) {
@@ -144,7 +144,7 @@ inline WireFormatLite::FieldType field_type(FieldType type) {
const MessageLite& ExtensionSet::GetMessage(int number,
const Descriptor* message_type,
MessageFactory* factory) const {
- map<int, Extension>::const_iterator iter = extensions_.find(number);
+ ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end() || iter->second.is_cleared) {
// Not present. Return the default value.
return *factory->GetPrototype(message_type);
@@ -187,7 +187,7 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
MessageFactory* factory) {
- map<int, Extension>::iterator iter = extensions_.find(descriptor->number());
+ ExtensionMap::iterator iter = extensions_.find(descriptor->number());
if (iter == extensions_.end()) {
// Not present. Return NULL.
return NULL;
@@ -213,6 +213,29 @@ MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
}
}
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+ const FieldDescriptor* descriptor, MessageFactory* factory) {
+ ExtensionMap::iterator iter = extensions_.find(descriptor->number());
+ if (iter == extensions_.end()) {
+ // Not present. Return NULL.
+ return NULL;
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+ MessageLite* ret = NULL;
+ if (iter->second.is_lazy) {
+ ret = iter->second.lazymessage_value->UnsafeArenaReleaseMessage(
+ *factory->GetPrototype(descriptor->message_type()));
+ if (arena_ == NULL) {
+ delete iter->second.lazymessage_value;
+ }
+ } else {
+ ret = iter->second.message_value;
+ }
+ extensions_.erase(descriptor->number());
+ return ret;
+ }
+}
+
ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) {
Extension* extension;
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
@@ -319,7 +342,7 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
int ExtensionSet::SpaceUsedExcludingSelf() const {
int total_size =
extensions_.size() * sizeof(map<int, Extension>::value_type);
- for (map<int, Extension>::const_iterator iter = extensions_.begin(),
+ for (ExtensionMap::const_iterator iter = extensions_.begin(),
end = extensions_.end();
iter != end;
++iter) {
@@ -386,31 +409,31 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
// The Serialize*ToArray methods are only needed in the heavy library, as
// the lite library only generates SerializeWithCachedSizes.
-uint8* ExtensionSet::SerializeWithCachedSizesToArray(
+uint8* ExtensionSet::InternalSerializeWithCachedSizesToArray(
int start_field_number, int end_field_number,
- uint8* target) const {
- map<int, Extension>::const_iterator iter;
+ bool deterministic, uint8* target) const {
+ ExtensionMap::const_iterator iter;
for (iter = extensions_.lower_bound(start_field_number);
iter != extensions_.end() && iter->first < end_field_number;
++iter) {
- target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first,
- target);
+ target = iter->second.InternalSerializeFieldWithCachedSizesToArray(
+ iter->first, deterministic, target);
}
return target;
}
-uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
- uint8* target) const {
- map<int, Extension>::const_iterator iter;
+uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+ bool deterministic, uint8* target) const {
+ ExtensionMap::const_iterator iter;
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
- target = iter->second.SerializeMessageSetItemWithCachedSizesToArray(
- iter->first, target);
+ target = iter->second.InternalSerializeMessageSetItemWithCachedSizesToArray(
+ iter->first, deterministic, target);
}
return target;
}
-uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
- int number, uint8* target) const {
+uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+ int number, bool deterministic, uint8* target) const {
if (is_repeated) {
if (is_packed) {
if (cached_size == 0) return target;
@@ -477,6 +500,16 @@ uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
HANDLE_TYPE( STRING, String, string);
HANDLE_TYPE( BYTES, Bytes, string);
HANDLE_TYPE( ENUM, Enum, enum);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
+ case FieldDescriptor::TYPE_##UPPERCASE: \
+ for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+ target = WireFormatLite::InternalWrite##CAMELCASE##ToArray( \
+ number, repeated_##LOWERCASE##_value->Get(i), \
+ deterministic, target); \
+ } \
+ break
+
HANDLE_TYPE( GROUP, Group, message);
HANDLE_TYPE( MESSAGE, Message, message);
#undef HANDLE_TYPE
@@ -510,10 +543,11 @@ uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
#undef HANDLE_TYPE
case FieldDescriptor::TYPE_MESSAGE:
if (is_lazy) {
- target = lazymessage_value->WriteMessageToArray(number, target);
+ target = lazymessage_value->InternalWriteMessageToArray(
+ number, deterministic, target);
} else {
- target = WireFormatLite::WriteMessageToArray(
- number, *message_value, target);
+ target = WireFormatLite::InternalWriteMessageToArray(
+ number, *message_value, deterministic, target);
}
break;
}
@@ -521,13 +555,14 @@ uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
return target;
}
-uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
- int number,
- uint8* target) const {
+uint8*
+ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
+ int number, bool deterministic, uint8* target) const {
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
// Not a valid MessageSet extension, but serialize it the normal way.
GOOGLE_LOG(WARNING) << "Invalid message set extension.";
- return SerializeFieldWithCachedSizesToArray(number, target);
+ return InternalSerializeFieldWithCachedSizesToArray(number, deterministic,
+ target);
}
if (is_cleared) return target;
@@ -732,7 +767,7 @@ int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
void ExtensionSet::SerializeMessageSetWithCachedSizes(
io::CodedOutputStream* output) const {
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
}
@@ -741,7 +776,7 @@ void ExtensionSet::SerializeMessageSetWithCachedSizes(
int ExtensionSet::MessageSetByteSize() const {
int total_size = 0;
- for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
total_size += iter->second.MessageSetItemByteSize(iter->first);
}
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index f40fcbc2..688afedb 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -205,6 +205,74 @@ TEST(ExtensionSetTest, ReleaseExtension) {
delete released_extension;
}
+TEST(ExtensionSetTest, ArenaUnsafeArenaSetAllocatedAndRelease) {
+ ::google::protobuf::Arena arena;
+ unittest::TestAllExtensions* message =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+ unittest::ForeignMessage extension;
+ message->UnsafeArenaSetAllocatedExtension(
+ unittest::optional_foreign_message_extension,
+ &extension);
+ // No copy when set.
+ unittest::ForeignMessage* mutable_extension =
+ message->MutableExtension(unittest::optional_foreign_message_extension);
+ EXPECT_EQ(&extension, mutable_extension);
+ // No copy when unsafe released.
+ unittest::ForeignMessage* released_extension =
+ message->UnsafeArenaReleaseExtension(
+ unittest::optional_foreign_message_extension);
+ EXPECT_EQ(&extension, released_extension);
+ EXPECT_FALSE(message->HasExtension(
+ unittest::optional_foreign_message_extension));
+ // Set the ownership back and let the destructors run. It should not take
+ // ownership, so this should not crash.
+ message->UnsafeArenaSetAllocatedExtension(
+ unittest::optional_foreign_message_extension,
+ &extension);
+}
+
+TEST(ExtensionSetTest, UnsafeArenaSetAllocatedAndRelease) {
+ unittest::TestAllExtensions message;
+ unittest::ForeignMessage* extension = new unittest::ForeignMessage();
+ message.UnsafeArenaSetAllocatedExtension(
+ unittest::optional_foreign_message_extension,
+ extension);
+ // No copy when set.
+ unittest::ForeignMessage* mutable_extension =
+ message.MutableExtension(unittest::optional_foreign_message_extension);
+ EXPECT_EQ(extension, mutable_extension);
+ // No copy when unsafe released.
+ unittest::ForeignMessage* released_extension =
+ message.UnsafeArenaReleaseExtension(
+ unittest::optional_foreign_message_extension);
+ EXPECT_EQ(extension, released_extension);
+ EXPECT_FALSE(message.HasExtension(
+ unittest::optional_foreign_message_extension));
+ // Set the ownership back and let the destructors run. It should take
+ // ownership, so this should not leak.
+ message.UnsafeArenaSetAllocatedExtension(
+ unittest::optional_foreign_message_extension,
+ extension);
+}
+
+TEST(ExtensionSetTest, ArenaUnsafeArenaReleaseOfHeapAlloc) {
+ ::google::protobuf::Arena arena;
+ unittest::TestAllExtensions* message =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+ unittest::ForeignMessage* extension = new unittest::ForeignMessage;
+ message->SetAllocatedExtension(
+ unittest::optional_foreign_message_extension,
+ extension);
+ // The arena should maintain ownership of the heap allocated proto because we
+ // used UnsafeArenaReleaseExtension. The leak checker will ensure this.
+ unittest::ForeignMessage* released_extension =
+ message->UnsafeArenaReleaseExtension(
+ unittest::optional_foreign_message_extension);
+ EXPECT_EQ(extension, released_extension);
+ EXPECT_FALSE(message->HasExtension(
+ unittest::optional_foreign_message_extension));
+}
+
TEST(ExtensionSetTest, CopyFrom) {
unittest::TestAllExtensions message1, message2;
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index c49ebceb..d197b406 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -245,8 +245,8 @@ void FieldMask::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FieldMask)
}
-::google::protobuf::uint8* FieldMask::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldMask::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
// repeated string paths = 1;
for (int i = 0; i < this->paths_size(); i++) {
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index f5e0b655..7a19c4aa 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -41,7 +41,7 @@ class FieldMask;
// ===================================================================
-class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
public:
FieldMask();
virtual ~FieldMask();
@@ -75,7 +75,11 @@ class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
index 6af6dbe8..c51de09a 100644
--- a/src/google/protobuf/field_mask.proto
+++ b/src/google/protobuf/field_mask.proto
@@ -107,6 +107,58 @@ option java_generate_equals_and_hash = true;
// describe the updated values, the API ignores the values of all
// fields not covered by the mask.
//
+// If a repeated field is specified for an update operation, the existing
+// repeated values in the target resource will be overwritten by the new values.
+// Note that a repeated field is only allowed in the last position of a field
+// mask.
+//
+// If a sub-message is specified in the last position of the field mask for an
+// update operation, then the existing sub-message in the target resource is
+// overwritten. Given the target message:
+//
+// f {
+// b {
+// d : 1
+// x : 2
+// }
+// c : 1
+// }
+//
+// And an update message:
+//
+// f {
+// b {
+// d : 10
+// }
+// }
+//
+// then if the field mask is:
+//
+// paths: "f.b"
+//
+// then the result will be:
+//
+// f {
+// b {
+// d : 10
+// }
+// c : 1
+// }
+//
+// However, if the update mask was:
+//
+// paths: "f.b.d"
+//
+// then the result would be:
+//
+// f {
+// b {
+// d : 10
+// x : 2
+// }
+// c : 1
+// }
+//
// In order to reset a field's value to the default, the field must
// be in the mask and set to the default value in the provided resource.
// Hence, in order to reset all fields of a resource, provide a default
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 2313181c..347bac5a 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1579,7 +1579,8 @@ Message* GeneratedMessageReflection::UnsafeArenaReleaseMessage(
if (field->is_extension()) {
return static_cast<Message*>(
- MutableExtensionSet(message)->ReleaseMessage(field, factory));
+ MutableExtensionSet(message)->UnsafeArenaReleaseMessage(field,
+ factory));
} else {
ClearBit(message, field);
if (field->containing_oneof()) {
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index 85ebdef1..6276b667 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -795,6 +795,73 @@ TEST(GeneratedMessageReflectionTest, ReleaseOneofMessageTest) {
EXPECT_TRUE(released == NULL);
}
+TEST(GeneratedMessageReflectionTest, ArenaReleaseMessageTest) {
+ ::google::protobuf::Arena arena;
+ unittest::TestAllTypes* message =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllTypes::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(message);
+ message->Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseExtensionMessageTest) {
+ ::google::protobuf::Arena arena;
+ unittest::TestAllExtensions* message =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+ TestUtil::ReflectionTester reflection_tester(
+ unittest::TestAllExtensions::descriptor());
+
+ // When nothing is set, we expect all released messages to be NULL.
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::IS_NULL);
+
+ // After fields are set we should get non-NULL releases.
+ reflection_tester.SetAllFieldsViaReflection(message);
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::NOT_NULL);
+
+ // After Clear() we may or may not get a message from ReleaseMessage().
+ // This is implementation specific.
+ reflection_tester.SetAllFieldsViaReflection(message);
+ message->Clear();
+ reflection_tester.ExpectMessagesReleasedViaReflection(
+ message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseOneofMessageTest) {
+ ::google::protobuf::Arena arena;
+ unittest::TestOneof2* message =
+ ::google::protobuf::Arena::CreateMessage<unittest::TestOneof2>(&arena);
+ TestUtil::ReflectionTester::SetOneofViaReflection(message);
+
+ const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+ const Reflection* reflection = message->GetReflection();
+ Message* released = reflection->ReleaseMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message"));
+
+ EXPECT_TRUE(released != NULL);
+ delete released;
+
+ released = reflection->ReleaseMessage(
+ message, descriptor->FindFieldByName("foo_lazy_message"));
+ EXPECT_TRUE(released == NULL);
+}
+
#ifdef PROTOBUF_HAS_DEATH_TEST
TEST(GeneratedMessageReflectionTest, UsageErrors) {
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index d8354c1f..148eee0e 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -376,6 +376,49 @@ inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
return std::make_pair(true, ptr);
}
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE::std::pair<bool, const uint8*> ReadVarint64FromArray(
+ const uint8* buffer, uint64* value);
+inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
+ const uint8* buffer, uint64* value) {
+ const uint8* ptr = buffer;
+ uint32 b;
+
+ // Splitting into 32-bit pieces gives better performance on 32-bit
+ // processors.
+ uint32 part0 = 0, part1 = 0, part2 = 0;
+
+ b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
+ part0 -= 0x80;
+ b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 7;
+ b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 14;
+ b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
+ part0 -= 0x80 << 21;
+ b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
+ part1 -= 0x80;
+ b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 7;
+ b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 14;
+ b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
+ part1 -= 0x80 << 21;
+ b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
+ part2 -= 0x80;
+ b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
+ // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
+
+ // We have overrun the maximum size of a varint (10 bytes). Assume
+ // the data is corrupt.
+ return std::make_pair(false, ptr);
+
+ done:
+ *value = (static_cast<uint64>(part0)) |
+ (static_cast<uint64>(part1) << 28) |
+ (static_cast<uint64>(part2) << 56);
+ return std::make_pair(true, ptr);
+}
+
} // namespace
bool CodedInputStream::ReadVarint32Slow(uint32* value) {
@@ -408,6 +451,32 @@ int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
}
}
+int CodedInputStream::ReadVarintSizeAsIntSlow() {
+ // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+ // for one-byte varints.
+ std::pair<uint64, bool> p = ReadVarint64Fallback();
+ if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
+ return p.first;
+}
+
+int CodedInputStream::ReadVarintSizeAsIntFallback() {
+ if (BufferSize() >= kMaxVarintBytes ||
+ // Optimization: We're also safe if the buffer is non-empty and it ends
+ // with a byte that would terminate a varint.
+ (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+ uint64 temp;
+ ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
+ if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
+ buffer_ = p.second;
+ return temp;
+ } else {
+ // Really slow case: we will incur the cost of an extra function call here,
+ // but moving this out of line reduces the size of this function, which
+ // improves the common case. In micro benchmarks, this is worth about 10-15%
+ return ReadVarintSizeAsIntSlow();
+ }
+}
+
uint32 CodedInputStream::ReadTagSlow() {
if (buffer_ == buffer_end_) {
// Call refresh.
@@ -499,47 +568,13 @@ std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
- // Fast path: We have enough bytes left in the buffer to guarantee that
- // this read won't cross the end, so we can skip the checks.
-
- const uint8* ptr = buffer_;
- uint32 b;
-
- // Splitting into 32-bit pieces gives better performance on 32-bit
- // processors.
- uint32 part0 = 0, part1 = 0, part2 = 0;
-
- b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
- part0 -= 0x80;
- b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
- part0 -= 0x80 << 7;
- b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
- part0 -= 0x80 << 14;
- b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
- part0 -= 0x80 << 21;
- b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
- part1 -= 0x80;
- b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
- part1 -= 0x80 << 7;
- b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
- part1 -= 0x80 << 14;
- b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
- part1 -= 0x80 << 21;
- b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
- part2 -= 0x80;
- b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
- // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
-
- // We have overrun the maximum size of a varint (10 bytes). The data
- // must be corrupt.
- return std::make_pair(0, false);
-
- done:
- Advance(ptr - buffer_);
- return std::make_pair((static_cast<uint64>(part0)) |
- (static_cast<uint64>(part1) << 28) |
- (static_cast<uint64>(part2) << 56),
- true);
+ uint64 temp;
+ ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
+ if (!p.first) {
+ return std::make_pair(0, false);
+ }
+ buffer_ = p.second;
+ return std::make_pair(temp, true);
} else {
uint64 temp;
bool success = ReadVarint64Slow(&temp);
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index c81a33ac..eb320745 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -237,6 +237,17 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Read an unsigned integer with Varint encoding.
bool ReadVarint64(uint64* value);
+ // Reads a varint off the wire into an "int". This should be used for reading
+ // sizes off the wire (sizes of strings, submessages, bytes fields, etc).
+ //
+ // The value from the wire is interpreted as unsigned. If its value exceeds
+ // the representable value of an integer on this platform, instead of
+ // truncating we return false. Truncating (as performed by ReadVarint32()
+ // above) is an acceptable approach for fields representing an integer, but
+ // when we are parsing a size from the wire, truncating the value would result
+ // in us misparsing the payload.
+ bool ReadVarintSizeAsInt(int* value);
+
// Read a tag. This calls ReadVarint32() and returns the result, or returns
// zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates
// the last tag value, which can be checked with LastTagWas().
@@ -594,9 +605,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// if it fails and the uint32 it read otherwise. The latter has a bool
// indicating success or failure as part of its return type.
int64 ReadVarint32Fallback(uint32 first_byte_or_zero);
+ int ReadVarintSizeAsIntFallback();
std::pair<uint64, bool> ReadVarint64Fallback();
bool ReadVarint32Slow(uint32* value);
bool ReadVarint64Slow(uint64* value);
+ int ReadVarintSizeAsIntSlow();
bool ReadLittleEndian32Fallback(uint32* value);
bool ReadLittleEndian64Fallback(uint64* value);
// Fallback/slow methods for reading tags. These do not update last_tag_,
@@ -868,6 +881,19 @@ inline bool CodedInputStream::ReadVarint64(uint64* value) {
return p.second;
}
+inline bool CodedInputStream::ReadVarintSizeAsInt(int* value) {
+ if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+ int v = *buffer_;
+ if (v < 0x80) {
+ *value = v;
+ Advance(1);
+ return true;
+ }
+ }
+ *value = ReadVarintSizeAsIntFallback();
+ return *value >= 0;
+}
+
// static
inline const uint8* CodedInputStream::ReadLittleEndian32FromArray(
const uint8* buffer,
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 2ba84559..e78e2efd 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -200,6 +200,26 @@ class LIBPROTOBUF_EXPORT Printer {
Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
}
+ // Link a subsitution variable emitted by the last call to Print to the file
+ // with path file_name.
+ void Annotate(const char* varname, const string& file_name) {
+ Annotate(varname, varname, file_name);
+ }
+
+ // Link the output range defined by the substitution variables as emitted by
+ // the last call to Print to the file with path file_name. The range begins
+ // at begin_varname's value and ends after the last character of the value
+ // substituted for end_varname.
+ void Annotate(const char* begin_varname, const char* end_varname,
+ const string& file_name) {
+ if (annotation_collector_ == NULL) {
+ // Annotations aren't turned on for this Printer.
+ return;
+ }
+ vector<int> empty_path;
+ Annotate(begin_varname, end_varname, file_name, empty_path);
+ }
+
// Print some text after applying variable substitutions. If a particular
// variable in the text is not defined, this will crash. Variables to be
// substituted are identified by their names surrounded by delimiter
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
index 9d81ccfb..e4d6a024 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -53,7 +53,6 @@
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/stl_util.h>
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 31593c1a..42bcfd94 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -520,7 +520,7 @@ class Map {
typedef size_t size_type;
typedef hash<Key> hasher;
- Map(bool old_style = true)
+ explicit Map(bool old_style = true)
: arena_(NULL),
default_enum_value_(0),
old_style_(old_style) {
@@ -1621,6 +1621,24 @@ class Map {
return *this;
}
+ void swap(Map& other) {
+ if (arena_ == other.arena_ && old_style_ == other.old_style_) {
+ std::swap(default_enum_value_, other.default_enum_value_);
+ if (old_style_) {
+ std::swap(deprecated_elements_, other.deprecated_elements_);
+ } else {
+ std::swap(elements_, other.elements_);
+ }
+ } else {
+ // TODO(zuguang): optimize this. The temporary copy can be allocated
+ // in the same arena as the other message, and the "other = copy" can
+ // be replaced with the fast-path swap above.
+ Map copy = *this;
+ *this = other;
+ other = copy;
+ }
+ }
+
// Access to hasher. Currently this returns a copy, but it may
// be modified to return a const reference in the future.
hasher hash_function() const {
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
index 987c4e29..801e7522 100644
--- a/src/google/protobuf/map_entry.h
+++ b/src/google/protobuf/map_entry.h
@@ -166,8 +166,10 @@ class MapEntry : public MapEntryBase {
entry_lite_.SerializeWithCachedSizes(output);
}
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
- return entry_lite_.SerializeWithCachedSizesToArray(output);
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+ ::google::protobuf::uint8* output) const {
+ return entry_lite_.InternalSerializeWithCachedSizesToArray(deterministic,
+ output);
}
int GetCachedSize() const {
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 7cdf1b93..23ac7b8a 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -31,6 +31,7 @@
#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+#include <assert.h>
#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/wire_format_lite_inl.h>
@@ -54,6 +55,38 @@ class MapFieldLite;
namespace protobuf {
namespace internal {
+// MoveHelper::Move is used to set *dest. It copies *src, or moves it (in
+// the C++11 sense), or swaps it. *src is left in a sane state for
+// subsequent destruction, but shouldn't be used for anything.
+template <bool is_enum, bool is_message, bool is_stringlike, typename T>
+struct MoveHelper { // primitives
+ static void Move(T* src, T* dest) { *dest = *src; }
+};
+
+template <bool is_message, bool is_stringlike, typename T>
+struct MoveHelper<true, is_message, is_stringlike, T> { // enums
+ static void Move(T* src, T* dest) { *dest = *src; }
+ // T is an enum here, so allow conversions to and from int.
+ static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
+ static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
+};
+
+template <bool is_stringlike, typename T>
+struct MoveHelper<false, true, is_stringlike, T> { // messages
+ static void Move(T* src, T* dest) { dest->Swap(src); }
+};
+
+template <typename T>
+struct MoveHelper<false, false, true, T> { // strings and similar
+ static void Move(T* src, T* dest) {
+#if __cplusplus >= 201103L
+ *dest = std::move(*src);
+#else
+ dest->swap(*src);
+#endif
+ }
+};
+
// MapEntryLite is used to implement parsing and serialization of map for lite
// runtime.
template <typename Key, typename Value,
@@ -180,11 +213,17 @@ class MapEntryLite : public MessageLite {
ValueTypeHandler::Write(kValueFieldNumber, value(), output);
}
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
- output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
- output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+ ::google::protobuf::uint8* output) const {
+ output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(),
+ deterministic, output);
+ output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(),
+ deterministic, output);
return output;
}
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const {
int size = 0;
@@ -271,6 +310,108 @@ class MapEntryLite : public MessageLite {
arena, key, value);
}
+ // Parsing using MergePartialFromCodedStream, above, is not as
+ // efficient as it could be. This helper class provides a speedier way.
+ template <typename MapField, typename Map>
+ class Parser {
+ public:
+ explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
+
+ // This does what the typical MergePartialFromCodedStream() is expected to
+ // do, with the additional side-effect that if successful (i.e., if true is
+ // going to be its return value) it inserts the key-value pair into map_.
+ bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+ // Look for the expected thing: a key and then a value. If it fails,
+ // invoke the enclosing class's MergePartialFromCodedStream, or return
+ // false if that would be pointless.
+ if (input->ExpectTag(kKeyTag)) {
+ if (!KeyTypeHandler::Read(input, &key_)) {
+ return false;
+ }
+ // Peek at the next byte to see if it is kValueTag. If not, bail out.
+ const void* data;
+ int size;
+ input->GetDirectBufferPointerInline(&data, &size);
+ // We could use memcmp here, but we don't bother. The tag is one byte.
+ assert(kTagSize == 1);
+ if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
+ typename Map::size_type size = map_->size();
+ value_ptr_ = &(*map_)[key_];
+ if (GOOGLE_PREDICT_TRUE(size != map_->size())) {
+ // We created a new key-value pair. Fill in the value.
+ typedef
+ typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
+ input->Skip(kTagSize); // Skip kValueTag.
+ if (!ValueTypeHandler::Read(input,
+ reinterpret_cast<T>(value_ptr_))) {
+ map_->erase(key_); // Failure! Undo insertion.
+ return false;
+ }
+ if (input->ExpectAtEnd()) return true;
+ return ReadBeyondKeyValuePair(input);
+ }
+ }
+ } else {
+ key_ = Key();
+ }
+
+ entry_.reset(mf_->NewEntry());
+ *entry_->mutable_key() = key_;
+ if (!entry_->MergePartialFromCodedStream(input)) return false;
+ return UseKeyAndValueFromEntry();
+ }
+
+ const Key& key() const { return key_; }
+ const Value& value() const { return *value_ptr_; }
+
+ private:
+ bool UseKeyAndValueFromEntry() GOOGLE_ATTRIBUTE_COLD {
+ // Update key_ in case we need it later (because key() is called).
+ // This is potentially inefficient, especially if the key is
+ // expensive to copy (e.g., a long string), but this is a cold
+ // path, so it's not a big deal.
+ key_ = entry_->key();
+ value_ptr_ = &(*map_)[key_];
+ MoveHelper<ValueTypeHandler::kIsEnum,
+ ValueTypeHandler::kIsMessage,
+ ValueTypeHandler::kWireType ==
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ Value>::Move(entry_->mutable_value(), value_ptr_);
+ if (entry_->GetArena() != NULL) entry_.release();
+ return true;
+ }
+
+ // After reading a key and value successfully, and inserting that data
+ // into map_, we are not at the end of the input. This is unusual, but
+ // allowed by the spec.
+ bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input)
+ GOOGLE_ATTRIBUTE_COLD {
+ typedef MoveHelper<KeyTypeHandler::kIsEnum,
+ KeyTypeHandler::kIsMessage,
+ KeyTypeHandler::kWireType ==
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ Key> KeyMover;
+ typedef MoveHelper<ValueTypeHandler::kIsEnum,
+ ValueTypeHandler::kIsMessage,
+ ValueTypeHandler::kWireType ==
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ Value> ValueMover;
+ entry_.reset(mf_->NewEntry());
+ ValueMover::Move(value_ptr_, entry_->mutable_value());
+ map_->erase(key_);
+ KeyMover::Move(&key_, entry_->mutable_key());
+ if (!entry_->MergePartialFromCodedStream(input)) return false;
+ return UseKeyAndValueFromEntry();
+ }
+
+ MapField* const mf_;
+ Map* const map_;
+ Key key_;
+ Value* value_ptr_;
+ // On the fast path entry_ is not used.
+ google::protobuf::scoped_ptr<MapEntryLite> entry_;
+ };
+
protected:
void set_has_key() { _has_bits_[0] |= 0x00000001u; }
bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index 223d42f3..dd5061c4 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -47,8 +47,8 @@
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <gtest/gtest.h>
-
namespace google {
+
namespace protobuf {
namespace internal {
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 9d4d6c13..dccb31ca 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -50,7 +50,6 @@
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/testing/file.h>
#include <google/protobuf/arena_test_util.h>
@@ -77,6 +76,7 @@
#include <google/protobuf/util/time_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
+#include <gmock/gmock.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
@@ -915,6 +915,55 @@ TEST_P(MapImplTest, ConvertToStdVectorOfPairs) {
EXPECT_EQ(101, std_vec[0].second);
}
+TEST_P(MapImplTest, SwapSameStyle) {
+ Map<int32, int32> another(GetParam()); // same old_style_ value
+ map_[9398] = 41999;
+ another[9398] = 41999;
+ another[8070] = 42056;
+ another.swap(map_);
+ EXPECT_THAT(another, testing::UnorderedElementsAre(
+ testing::Pair(9398, 41999)));
+ EXPECT_THAT(map_, testing::UnorderedElementsAre(
+ testing::Pair(8070, 42056),
+ testing::Pair(9398, 41999)));
+}
+
+TEST_P(MapImplTest, SwapDifferentStyle) {
+ Map<int32, int32> another(!GetParam()); // different old_style_ value
+ map_[9398] = 41999;
+ another[9398] = 41999;
+ another[8070] = 42056;
+ another.swap(map_);
+ EXPECT_THAT(another, testing::UnorderedElementsAre(
+ testing::Pair(9398, 41999)));
+ EXPECT_THAT(map_, testing::UnorderedElementsAre(
+ testing::Pair(8070, 42056),
+ testing::Pair(9398, 41999)));
+}
+
+TEST_P(MapImplTest, SwapArena) {
+ Arena arena1, arena2;
+ Map<int32, int32> m1(&arena1, false);
+ Map<int32, int32> m2(&arena2, false);
+ map_[9398] = 41999;
+ m1[9398] = 41999;
+ m1[8070] = 42056;
+ m2[10244] = 10247;
+ m2[8070] = 42056;
+ m1.swap(map_);
+ EXPECT_THAT(m1, testing::UnorderedElementsAre(
+ testing::Pair(9398, 41999)));
+ EXPECT_THAT(map_, testing::UnorderedElementsAre(
+ testing::Pair(8070, 42056),
+ testing::Pair(9398, 41999)));
+ m2.swap(m1);
+ EXPECT_THAT(m1, testing::UnorderedElementsAre(
+ testing::Pair(8070, 42056),
+ testing::Pair(10244, 10247)));
+ EXPECT_THAT(m2, testing::UnorderedElementsAre(
+ testing::Pair(9398, 41999)));
+}
+
INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool());
// Map Field Reflection Test ========================================
@@ -2106,6 +2155,76 @@ TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
EXPECT_TRUE(message.ParseFromString(data));
EXPECT_EQ(1, message.map_int32_int32().size());
EXPECT_EQ(1, message.map_int32_int32().at(2));
+
+ // A similar test, but with a map from int to a message type.
+ // Again, we want to be sure that the "second one wins" when
+ // there are two separate entries with the same key.
+ const int key = 99;
+ unittest::TestRequiredMessageMap map_message;
+ unittest::TestRequired with_dummy4;
+ with_dummy4.set_a(0);
+ with_dummy4.set_b(0);
+ with_dummy4.set_c(0);
+ with_dummy4.set_dummy4(11);
+ (*map_message.mutable_map_field())[key] = with_dummy4;
+ string s = map_message.SerializeAsString();
+ unittest::TestRequired with_dummy5;
+ with_dummy5.set_a(0);
+ with_dummy5.set_b(0);
+ with_dummy5.set_c(0);
+ with_dummy5.set_dummy5(12);
+ (*map_message.mutable_map_field())[key] = with_dummy5;
+ string both = s + map_message.SerializeAsString();
+ // We don't expect a merge now. The "second one wins."
+ ASSERT_TRUE(map_message.ParseFromString(both));
+ ASSERT_EQ(1, map_message.map_field().size());
+ ASSERT_EQ(1, map_message.map_field().count(key));
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.a());
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.c());
+ EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4());
+ ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5());
+ EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Exhaustive combinations of keys, values, and junk in any order.
+// This re-tests some of the things tested above, but if it fails
+// it's more work to determine what went wrong, so it isn't necessarily
+// bad that we have the simpler tests too.
+TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) {
+ unittest::TestMap message;
+ const int kMaxNumKeysAndValuesAndJunk = 4;
+ const char kKeyTag = 0x08;
+ const char kValueTag = 0x10;
+ const char kJunkTag = 0x20;
+ for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) {
+ string data = "\x0A";
+ // Encode length of what will follow.
+ data.push_back(items * 2);
+ static const int kBitsOfIPerItem = 4;
+ static const int mask = (1 << kBitsOfIPerItem) - 1;
+ // Each iteration of the following is a test. It uses i as bit vector
+ // encoding the keys and values to put in the wire format.
+ for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) {
+ string wire_format = data;
+ int expected_key = 0;
+ int expected_value = 0;
+ for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) {
+ bool is_key = k & 0x1;
+ bool is_value = !is_key && (k & 0x2);
+ wire_format.push_back(is_key ? kKeyTag :
+ is_value ? kValueTag : kJunkTag);
+ char c = static_cast<char>(k & mask) >> 2; // One char after the tag.
+ wire_format.push_back(c);
+ if (is_key) expected_key = static_cast<int>(c);
+ if (is_value) expected_value = static_cast<int>(c);
+ ASSERT_TRUE(message.ParseFromString(wire_format));
+ ASSERT_EQ(1, message.map_int32_int32().size());
+ ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first);
+ ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second);
+ }
+ }
+ }
}
TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
@@ -2189,6 +2308,74 @@ TEST(GeneratedMapFieldTest, IsInitialized) {
EXPECT_TRUE(map_message.IsInitialized());
}
+TEST(GeneratedMapFieldTest, MessagesMustMerge) {
+ unittest::TestRequiredMessageMap map_message;
+ unittest::TestRequired with_dummy4;
+ with_dummy4.set_a(97);
+ with_dummy4.set_b(0);
+ with_dummy4.set_c(0);
+ with_dummy4.set_dummy4(98);
+
+ EXPECT_TRUE(with_dummy4.IsInitialized());
+ (*map_message.mutable_map_field())[0] = with_dummy4;
+ EXPECT_TRUE(map_message.IsInitialized());
+ string s = map_message.SerializeAsString();
+
+ // Modify s so that there are two values in the entry for key 0.
+ // The first will have no value for c. The second will have no value for a.
+ // Those are required fields. Also, make some other little changes, to
+ // ensure we are merging the two values (because they're messages).
+ ASSERT_EQ(s.size() - 2, s[1]); // encoding of the length of what follows
+ string encoded_val(s.data() + 4, s.data() + s.size());
+ // In s, change the encoding of c to an encoding of dummy32.
+ s[s.size() - 3] -= 8;
+ // Make encoded_val slightly different from what's in s.
+ encoded_val[encoded_val.size() - 1] += 33; // Encode c = 33.
+ for (int i = 0; i < encoded_val.size(); i++) {
+ if (encoded_val[i] == 97) {
+ // Encode b = 91 instead of a = 97. But this won't matter, because
+ // we also encode b = 0 right after this. The point is to leave out
+ // a required field, and make sure the parser doesn't complain, because
+ // every required field is set after the merge of the two values.
+ encoded_val[i - 1] += 16;
+ encoded_val[i] = 91;
+ } else if (encoded_val[i] == 98) {
+ // Encode dummy5 = 99 instead of dummy4 = 98.
+ encoded_val[i - 1] += 8; // The tag for dummy5 is 8 more.
+ encoded_val[i]++;
+ break;
+ }
+ }
+
+ s += encoded_val; // Add the second message.
+ s[1] += encoded_val.size(); // Adjust encoded size.
+
+ // Test key then value then value.
+ int key = 0;
+ ASSERT_TRUE(map_message.ParseFromString(s));
+ ASSERT_EQ(1, map_message.map_field().size());
+ ASSERT_EQ(1, map_message.map_field().count(key));
+ EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+ EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+ EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+ EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+
+ // Test key then value then value then key.
+ s.push_back(s[2]); // Copy the key's tag.
+ key = 19;
+ s.push_back(key); // Second key is 19 instead of 0.
+ s[1] += 2; // Adjust encoded size.
+ ASSERT_TRUE(map_message.ParseFromString(s));
+ ASSERT_EQ(1, map_message.map_field().size());
+ ASSERT_EQ(1, map_message.map_field().count(key));
+ EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+ EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+ EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+ EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+}
+
// Generated Message Reflection Test ================================
TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
@@ -2783,6 +2970,21 @@ TEST(ArenaTest, StringMapNoLeak) {
ASSERT_FALSE(message == NULL);
}
+TEST(ArenaTest, IsInitialized) {
+ // Allocate a large initial polluted block.
+ std::vector<char> arena_block(128 * 1024);
+ std::fill(arena_block.begin(), arena_block.end(), '\xff');
+
+ ArenaOptions options;
+ options.initial_block = &arena_block[0];
+ options.initial_block_size = arena_block.size();
+ Arena arena(options);
+
+ unittest::TestArenaMap* message =
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+ EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]);
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index f8ad7584..74e8bb50 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -164,6 +164,9 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
MapEntryAccessorType* value);
static inline void Write(int field, const MapEntryAccessorType& value,
io::CodedOutputStream* output);
+ static inline uint8* InternalWriteToArray(int field,
+ const MapEntryAccessorType& value,
+ bool deterministic, uint8* output);
static inline uint8* WriteToArray(int field,
const MapEntryAccessorType& value,
uint8* output);
@@ -220,9 +223,16 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
MapEntryAccessorType* value); \
static inline void Write(int field, const MapEntryAccessorType& value, \
io::CodedOutputStream* output); \
+ static inline uint8* InternalWriteToArray( \
+ int field, \
+ const MapEntryAccessorType& value, \
+ bool deterministic, \
+ uint8* output); \
static inline uint8* WriteToArray(int field, \
const MapEntryAccessorType& value, \
- uint8* output); \
+ uint8* output) { \
+ return InternalWriteToArray(field, value, false, output); \
+ } \
static inline const MapEntryAccessorType& GetExternalReference( \
const TypeOnMemory& value); \
static inline void DeleteNoArena(const TypeOnMemory& x); \
@@ -362,9 +372,11 @@ inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
template <typename Type>
inline uint8*
-MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray(
- int field, const MapEntryAccessorType& value, uint8* output) {
- return WireFormatLite::WriteMessageToArray(field, value, output);
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::InternalWriteToArray(
+ int field, const MapEntryAccessorType& value, bool deterministic,
+ uint8* output) {
+ return WireFormatLite::InternalWriteMessageToArray(field, value,
+ deterministic, output);
}
#define WRITE_METHOD(FieldType, DeclaredType) \
@@ -376,8 +388,9 @@ MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray(
} \
template <typename Type> \
inline uint8* \
- MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray( \
- int field, const MapEntryAccessorType& value, uint8* output) { \
+ MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
+ Type>::InternalWriteToArray( \
+ int field, const MapEntryAccessorType& value, bool, uint8* output) { \
return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
}
@@ -543,7 +556,7 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::MapEntryAccessorType& \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::GetExternalReference(const TypeOnMemory& value) { \
- return value.Get(&::google::protobuf::internal::GetEmptyString()); \
+ return value.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline int \
@@ -564,7 +577,8 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* arena) { \
- value->ClearToEmpty(&::google::protobuf::internal::GetEmptyString(), arena); \
+ value->ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), \
+ arena); \
} \
template <typename Type> \
inline void \
@@ -577,12 +591,12 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \
- to->Set(&::google::protobuf::internal::GetEmptyString(), from, arena); \
+ to->Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from, arena); \
} \
template <typename Type> \
void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \
TypeOnMemory& value) { \
- value.DestroyNoArena(&::google::protobuf::internal::GetEmptyString()); \
+ value.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
@@ -591,7 +605,8 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
inline void \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize( \
TypeOnMemory* value, Arena* arena) { \
- value->UnsafeSetDefault(&::google::protobuf::internal::GetEmptyString()); \
+ value->UnsafeSetDefault( \
+ &::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline void \
@@ -606,7 +621,8 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::MapEntryAccessorType* \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \
TypeOnMemory* value, Arena* arena) { \
- return value->Mutable(&::google::protobuf::internal::GetEmptyString(), arena); \
+ return value->Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), \
+ arena); \
} \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
@@ -615,7 +631,7 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::DefaultIfNotInitialized(const TypeOnMemory& value, \
const TypeOnMemory& \
default_value) { \
- return value.Get(&::google::protobuf::internal::GetEmptyString()); \
+ return value.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); \
} \
template <typename Type> \
inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index a4d9277e..dcdffe1c 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -585,8 +585,8 @@ class LIBPROTOBUF_EXPORT Reflection {
// If you have no idea what that meant, then you probably don't need to worry
// about it (don't provide a MessageFactory). WARNING: If the
// FieldDescriptor is for a compiled-in extension, then
- // factory->GetPrototype(field->message_type() MUST return an instance of the
- // compiled-in class for this type, NOT DynamicMessage.
+ // factory->GetPrototype(field->message_type()) MUST return an instance of
+ // the compiled-in class for this type, NOT DynamicMessage.
virtual Message* MutableMessage(Message* message,
const FieldDescriptor* field,
MessageFactory* factory = NULL) const = 0;
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 9d7b64f7..3913be1b 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -221,7 +221,8 @@ bool MessageLite::ParsePartialFromArray(const void* data, int size) {
// ===================================================================
-uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
+uint8* MessageLite::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, uint8* target) const {
// We only optimize this when using optimize_for = SPEED. In other cases
// we just use the CodedOutputStream path.
int size = GetCachedSize();
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 4c16f4c0..f606aeec 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -51,6 +51,9 @@ namespace io {
class ZeroCopyInputStream;
class ZeroCopyOutputStream;
}
+namespace internal {
+ class WireFormatLite;
+}
// Interface to light weight protocol messages.
//
@@ -249,10 +252,11 @@ class LIBPROTOBUF_EXPORT MessageLite {
virtual void SerializeWithCachedSizes(
io::CodedOutputStream* output) const = 0;
- // Like SerializeWithCachedSizes, but writes directly to *target, returning
- // a pointer to the byte immediately after the last byte written. "target"
- // must point at a byte array of at least ByteSize() bytes.
- virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
+ // A version of SerializeWithCachedSizesToArray, below, that does
+ // not guarantee deterministic serialization.
+ virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const {
+ return InternalSerializeWithCachedSizesToArray(false, target);
+ }
// Returns the result of the last call to ByteSize(). An embedded message's
// size is needed both to serialize it (because embedded messages are
@@ -267,7 +271,22 @@ class LIBPROTOBUF_EXPORT MessageLite {
// method.)
virtual int GetCachedSize() const = 0;
+ // Functions below here are not part of the public interface. It isn't
+ // enforced, but they should be treated as private, and will be private
+ // at some future time. Unfortunately the implementation of the "friend"
+ // keyword in GCC is broken at the moment, but we expect it will be fixed.
+
+ // Like SerializeWithCachedSizes, but writes directly to *target, returning
+ // a pointer to the byte immediately after the last byte written. "target"
+ // must point at a byte array of at least ByteSize() bytes. If deterministic
+ // is true then we use deterministic serialization, e.g., map keys are sorted.
+ // FOR INTERNAL USE ONLY!
+ virtual uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+ uint8* target) const;
+
private:
+ friend class internal::WireFormatLite;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
};
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 1961bc48..38358dbb 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -564,12 +564,16 @@ class GenericTypeHandler {
return ::google::protobuf::Arena::CreateMaybeMessage<Type>(
arena, static_cast<GenericType*>(0));
}
- // We force NewFromPrototype() and Delete() to be non-inline to reduce code
- // size: else, several other methods get inlined copies of message types'
- // constructors and destructors.
+ // We force NewFromPrototype() to be non-inline to reduce code size:
+ // else, several other methods get inlined copies of message types'
+ // constructors.
GOOGLE_ATTRIBUTE_NOINLINE static GenericType* NewFromPrototype(
const GenericType* prototype, ::google::protobuf::Arena* arena = NULL);
- GOOGLE_ATTRIBUTE_NOINLINE static void Delete(GenericType* value, Arena* arena);
+ static inline void Delete(GenericType* value, Arena* arena) {
+ if (arena == NULL) {
+ delete value;
+ }
+ }
static inline ::google::protobuf::Arena* GetArena(GenericType* value) {
return ::google::protobuf::Arena::GetArena<Type>(value);
}
@@ -594,12 +598,6 @@ GenericType* GenericTypeHandler<GenericType>::NewFromPrototype(
return New(arena);
}
template <typename GenericType>
-void GenericTypeHandler<GenericType>::Delete(GenericType* value, Arena* arena) {
- if (arena == NULL) {
- delete value;
- }
-}
-template <typename GenericType>
void GenericTypeHandler<GenericType>::Merge(const GenericType& from,
GenericType* to) {
to->MergeFrom(from);
@@ -1359,13 +1357,13 @@ inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(::google::protobuf::Arena* are
template <typename TypeHandler>
void RepeatedPtrFieldBase::Destroy() {
- if (rep_ != NULL) {
- for (int i = 0; i < rep_->allocated_size; i++) {
- TypeHandler::Delete(cast<TypeHandler>(rep_->elements[i]), arena_);
- }
- if (arena_ == NULL) {
- delete [] reinterpret_cast<char*>(rep_);
+ if (rep_ != NULL && arena_ == NULL) {
+ int n = rep_->allocated_size;
+ void* const* elements = rep_->elements;
+ for (int i = 0; i < n; i++) {
+ TypeHandler::Delete(cast<TypeHandler>(elements[i]), NULL);
}
+ delete[] reinterpret_cast<char*>(rep_);
}
rep_ = NULL;
}
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index c67cd102..4d8e77ce 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -244,8 +244,8 @@ void SourceContext::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.SourceContext)
}
-::google::protobuf::uint8* SourceContext::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceContext::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
// optional string file_name = 1;
if (this->file_name().size() > 0) {
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index ccfd365b..341a4534 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -41,7 +41,7 @@ class SourceContext;
// ===================================================================
-class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceContext) */ {
public:
SourceContext();
virtual ~SourceContext();
@@ -75,7 +75,11 @@ class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
index d76252ca..a2c08e2b 100644
--- a/src/google/protobuf/source_context.proto
+++ b/src/google/protobuf/source_context.proto
@@ -43,6 +43,6 @@ option objc_class_prefix = "GPB";
// protobuf element, like the file in which it is defined.
message SourceContext {
// The path-qualified name of the .proto file that contained the associated
- // protobuf element. For example: `"google/protobuf/source.proto"`.
+ // protobuf element. For example: `"google/protobuf/source_context.proto"`.
string file_name = 1;
}
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 11ccabbf..dd6b78d1 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -239,6 +239,7 @@ Struct::Struct(const Struct& from)
void Struct::SharedCtor() {
_is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
fields_.SetAssignDescriptorCallback(
protobuf_AssignDescriptorsOnce);
@@ -301,12 +302,16 @@ bool Struct::MergePartialFromCodedStream(
if (tag == 10) {
DO_(input->IncrementRecursionDepth());
parse_loop_fields:
- ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry(fields_.NewEntry());
+ Struct_FieldsEntry::Parser< ::google::protobuf::internal::MapField<
+ ::std::string, ::google::protobuf::Value,
+ ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+ ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+ 0 >,
+ ::google::protobuf::Map< ::std::string, ::google::protobuf::Value > > parser(&fields_);
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
- input, entry.get()));
- (*mutable_fields())[entry->key()].Swap(entry->mutable_value());
+ input, &parser));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
- entry->key().data(), entry->key().length(),
+ parser.key().data(), parser.key().length(),
::google::protobuf::internal::WireFormatLite::PARSE,
"google.protobuf.Struct.FieldsEntry.key"));
} else {
@@ -361,8 +366,8 @@ void Struct::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Struct)
}
-::google::protobuf::uint8* Struct::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Struct::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
// map<string, .google.protobuf.Value> fields = 1;
{
@@ -372,8 +377,8 @@ void Struct::SerializeWithCachedSizes(
it != this->fields().end(); ++it) {
entry.reset(fields_.NewEntryWrapper(it->first, it->second));
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 1, *entry, target);
+ InternalWriteMessageNoVirtualToArray(
+ 1, *entry, false, target);
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
it->first.data(), it->first.length(),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
@@ -774,8 +779,8 @@ void Value::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Value)
}
-::google::protobuf::uint8* Value::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Value::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
// optional .google.protobuf.NullValue null_value = 1;
if (has_null_value()) {
@@ -807,15 +812,15 @@ void Value::SerializeWithCachedSizes(
// optional .google.protobuf.Struct struct_value = 5;
if (has_struct_value()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 5, *kind_.struct_value_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 5, *kind_.struct_value_, false, target);
}
// optional .google.protobuf.ListValue list_value = 6;
if (has_list_value()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 6, *kind_.list_value_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 6, *kind_.list_value_, false, target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
@@ -1367,14 +1372,14 @@ void ListValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.ListValue)
}
-::google::protobuf::uint8* ListValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ListValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
// repeated .google.protobuf.Value values = 1;
for (unsigned int i = 0, n = this->values_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 1, this->values(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 1, this->values(i), false, target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 6a4764a7..b085b849 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -66,7 +66,7 @@ inline bool NullValue_Parse(
}
// ===================================================================
-class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Struct) */ {
public:
Struct();
virtual ~Struct();
@@ -100,7 +100,11 @@ class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -158,7 +162,7 @@ class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Value) */ {
public:
Value();
virtual ~Value();
@@ -202,7 +206,11 @@ class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -320,7 +328,7 @@ class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ListValue) */ {
public:
ListValue();
virtual ~ListValue();
@@ -354,7 +362,11 @@ class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/stubs/mathlimits.h b/src/google/protobuf/stubs/mathlimits.h
index d9846940..70e47bff 100644
--- a/src/google/protobuf/stubs/mathlimits.h
+++ b/src/google/protobuf/stubs/mathlimits.h
@@ -230,11 +230,11 @@ DECL_UNSIGNED_INT_LIMITS(unsigned long long int)
static bool IsNegInf(const Type x) { return _fpclass(x) == _FPCLASS_NINF; }
#else
#define DECL_FP_LIMIT_FUNCS \
- static bool IsFinite(const Type x) { return !isinf(x) && !isnan(x); } \
+ static bool IsFinite(const Type x) { return !isinf(x) && !isnan(x); } \
static bool IsNaN(const Type x) { return isnan(x); } \
static bool IsInf(const Type x) { return isinf(x); } \
- static bool IsPosInf(const Type x) { return isinf(x) && x > 0; } \
- static bool IsNegInf(const Type x) { return isinf(x) && x < 0; }
+ static bool IsPosInf(const Type x) { return isinf(x) && x > 0; } \
+ static bool IsNegInf(const Type x) { return isinf(x) && x < 0; }
#endif
// We can't put floating-point constant values in the header here because
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index 0e65fc8f..328258b7 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -174,6 +174,15 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
#endif
#endif
+#ifndef GOOGLE_ATTRIBUTE_NORETURN
+#ifdef __GNUC__
+// Tell the compiler that a given function never returns.
+#define GOOGLE_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#else
+#define GOOGLE_ATTRIBUTE_NORETURN
+#endif
+#endif
+
#ifndef GOOGLE_ATTRIBUTE_DEPRECATED
#ifdef __GNUC__
// If the method/variable/type is used anywhere, produce a warning.
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index 07aa1d77..658c8ee2 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -3332,7 +3332,11 @@ void TestUtil::ReflectionTester::ExpectMessagesReleasedViaReflection(
break;
case NOT_NULL:
EXPECT_TRUE(released != NULL);
- EXPECT_EQ(&sub_message, released);
+ if (message->GetArena() == NULL) {
+ // released message must be same as sub_message if source message is
+ // not on arena.
+ EXPECT_EQ(&sub_message, released);
+ }
break;
case CAN_BE_NULL:
break;
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index 2b9cddef..d45706b6 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -66,6 +66,9 @@ namespace protobuf {
string TestSourceDir() {
#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+#ifdef GOOGLE_PROTOBUF_TEST_SOURCE_PATH
+ return GOOGLE_PROTOBUF_TEST_SOURCE_PATH;
+#else
#ifndef _MSC_VER
// automake sets the "srcdir" environment variable.
char* result = getenv("srcdir");
@@ -86,6 +89,7 @@ string TestSourceDir() {
prefix += "/..";
}
return prefix + "/src";
+#endif // GOOGLE_PROTOBUF_TEST_SOURCE_PATH
#else
return "third_party/protobuf/src";
#endif // GOOGLE_THIRD_PARTY_PROTOBUF
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index c0dfd53f..d49d8588 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -234,7 +234,8 @@ class TextFormat::Parser::ParserImpl {
bool allow_unknown_field,
bool allow_unknown_enum,
bool allow_field_number,
- bool allow_relaxed_whitespace)
+ bool allow_relaxed_whitespace,
+ bool allow_partial)
: error_collector_(error_collector),
finder_(finder),
parse_info_tree_(parse_info_tree),
@@ -246,6 +247,7 @@ class TextFormat::Parser::ParserImpl {
allow_unknown_field_(allow_unknown_field),
allow_unknown_enum_(allow_unknown_enum),
allow_field_number_(allow_field_number),
+ allow_partial_(allow_partial),
had_errors_(false) {
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats.
@@ -718,7 +720,8 @@ class TextFormat::Parser::ParserImpl {
value = SimpleItoa(int_value); // for error reporting
enum_value = enum_type->FindValueByNumber(int_value);
} else {
- ReportError("Expected integer or identifier.");
+ ReportError("Expected integer or identifier, got: " +
+ tokenizer_.current().text);
return false;
}
@@ -831,7 +834,7 @@ class TextFormat::Parser::ParserImpl {
return true;
}
- ReportError("Expected identifier.");
+ ReportError("Expected identifier, got: " + tokenizer_.current().text);
return false;
}
@@ -851,7 +854,7 @@ class TextFormat::Parser::ParserImpl {
// Returns false if the token is not of type STRING.
bool ConsumeString(string* text) {
if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
- ReportError("Expected string.");
+ ReportError("Expected string, got: " + tokenizer_.current().text);
return false;
}
@@ -869,13 +872,13 @@ class TextFormat::Parser::ParserImpl {
// Returns false if the token is not of type INTEGER.
bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
- ReportError("Expected integer.");
+ ReportError("Expected integer, got: " + tokenizer_.current().text);
return false;
}
if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
max_value, value)) {
- ReportError("Integer out of range.");
+ ReportError("Integer out of range (" + tokenizer_.current().text + ")");
return false;
}
@@ -902,10 +905,14 @@ class TextFormat::Parser::ParserImpl {
DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
- *value = static_cast<int64>(unsigned_value);
-
if (negative) {
- *value = -*value;
+ if ((static_cast<uint64>(kint64max) + 1) == unsigned_value) {
+ *value = kint64min;
+ } else {
+ *value = -static_cast<int64>(unsigned_value);
+ }
+ } else {
+ *value = static_cast<int64>(unsigned_value);
}
return true;
@@ -915,18 +922,18 @@ class TextFormat::Parser::ParserImpl {
// Accepts decimal numbers only, rejects hex or oct numbers.
bool ConsumeUnsignedDecimalInteger(uint64* value, uint64 max_value) {
if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
- ReportError("Expected integer.");
+ ReportError("Expected integer, got: " + tokenizer_.current().text);
return false;
}
const string& text = tokenizer_.current().text;
if (IsHexNumber(text) || IsOctNumber(text)) {
- ReportError("Expect a decimal number.");
+ ReportError("Expect a decimal number, got: " + text);
return false;
}
if (!io::Tokenizer::ParseInteger(text, max_value, value)) {
- ReportError("Integer out of range.");
+ ReportError("Integer out of range (" + text + ")");
return false;
}
@@ -971,11 +978,11 @@ class TextFormat::Parser::ParserImpl {
*value = std::numeric_limits<double>::quiet_NaN();
tokenizer_.Next();
} else {
- ReportError("Expected double.");
+ ReportError("Expected double, got: " + text);
return false;
}
} else {
- ReportError("Expected double.");
+ ReportError("Expected double, got: " + tokenizer_.current().text);
return false;
}
@@ -1033,7 +1040,17 @@ class TextFormat::Parser::ParserImpl {
DO(ConsumeMessageDelimiter(&sub_delimiter));
DO(ConsumeMessage(value.get(), sub_delimiter));
- value->AppendToString(serialized_value);
+ if (allow_partial_) {
+ value->AppendPartialToString(serialized_value);
+ } else {
+ if (!value->IsInitialized()) {
+ ReportError(
+ "Value of type \"" + full_type_name +
+ "\" stored in google.protobuf.Any has missing required fields");
+ return false;
+ }
+ value->AppendToString(serialized_value);
+ }
return true;
}
@@ -1098,6 +1115,7 @@ class TextFormat::Parser::ParserImpl {
const bool allow_unknown_field_;
const bool allow_unknown_enum_;
const bool allow_field_number_;
+ const bool allow_partial_;
bool had_errors_;
};
@@ -1259,7 +1277,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
overwrites_policy,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return MergeUsingImpl(input, output, &parser);
}
@@ -1276,7 +1294,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return MergeUsingImpl(input, output, &parser);
}
@@ -1310,7 +1328,7 @@ bool TextFormat::Parser::ParseFieldValueFromString(
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return parser.ParseField(field, output);
}
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 410e5480..c9521cc3 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -1196,11 +1196,13 @@ TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
TEST_F(TextFormatParserTest, InvalidToken) {
- ExpectFailure("optional_bool: true\n-5\n", "Expected identifier.",
+ ExpectFailure("optional_bool: true\n-5\n", "Expected identifier, got: -",
2, 1);
- ExpectFailure("optional_bool: true!\n", "Expected identifier.", 1, 20);
- ExpectFailure("\"some string\"", "Expected identifier.", 1, 1);
+ ExpectFailure("optional_bool: true!\n", "Expected identifier, got: !", 1,
+ 20);
+ ExpectFailure("\"some string\"",
+ "Expected identifier, got: \"some string\"", 1, 1);
}
TEST_F(TextFormatParserTest, InvalidFieldName) {
@@ -1248,46 +1250,52 @@ TEST_F(TextFormatParserTest, AllowIgnoreCapitalizationError) {
TEST_F(TextFormatParserTest, InvalidFieldValues) {
// Invalid values for a double/float field.
- ExpectFailure("optional_double: \"hello\"\n", "Expected double.", 1, 18);
- ExpectFailure("optional_double: true\n", "Expected double.", 1, 18);
- ExpectFailure("optional_double: !\n", "Expected double.", 1, 18);
+ ExpectFailure("optional_double: \"hello\"\n",
+ "Expected double, got: \"hello\"", 1, 18);
+ ExpectFailure("optional_double: true\n", "Expected double, got: true", 1,
+ 18);
+ ExpectFailure("optional_double: !\n", "Expected double, got: !", 1, 18);
ExpectFailure("optional_double {\n \n}\n", "Expected \":\", found \"{\".",
1, 17);
// Invalid values for a signed integer field.
- ExpectFailure("optional_int32: \"hello\"\n", "Expected integer.", 1, 17);
- ExpectFailure("optional_int32: true\n", "Expected integer.", 1, 17);
- ExpectFailure("optional_int32: 4.5\n", "Expected integer.", 1, 17);
- ExpectFailure("optional_int32: !\n", "Expected integer.", 1, 17);
+ ExpectFailure("optional_int32: \"hello\"\n",
+ "Expected integer, got: \"hello\"", 1, 17);
+ ExpectFailure("optional_int32: true\n", "Expected integer, got: true", 1, 17);
+ ExpectFailure("optional_int32: 4.5\n", "Expected integer, got: 4.5", 1, 17);
+ ExpectFailure("optional_int32: !\n", "Expected integer, got: !", 1, 17);
ExpectFailure("optional_int32 {\n \n}\n", "Expected \":\", found \"{\".",
1, 16);
ExpectFailure("optional_int32: 0x80000000\n",
- "Integer out of range.", 1, 17);
+ "Integer out of range (0x80000000)", 1, 17);
ExpectFailure("optional_int64: 0x8000000000000000\n",
- "Integer out of range.", 1, 17);
+ "Integer out of range (0x8000000000000000)", 1, 17);
ExpectFailure("optional_int32: -0x80000001\n",
- "Integer out of range.", 1, 18);
+ "Integer out of range (0x80000001)", 1, 18);
ExpectFailure("optional_int64: -0x8000000000000001\n",
- "Integer out of range.", 1, 18);
+ "Integer out of range (0x8000000000000001)", 1, 18);
// Invalid values for an unsigned integer field.
- ExpectFailure("optional_uint64: \"hello\"\n", "Expected integer.", 1, 18);
- ExpectFailure("optional_uint64: true\n", "Expected integer.", 1, 18);
- ExpectFailure("optional_uint64: 4.5\n", "Expected integer.", 1, 18);
- ExpectFailure("optional_uint64: -5\n", "Expected integer.", 1, 18);
- ExpectFailure("optional_uint64: !\n", "Expected integer.", 1, 18);
+ ExpectFailure("optional_uint64: \"hello\"\n",
+ "Expected integer, got: \"hello\"", 1, 18);
+ ExpectFailure("optional_uint64: true\n",
+ "Expected integer, got: true", 1, 18);
+ ExpectFailure("optional_uint64: 4.5\n", "Expected integer, got: 4.5", 1, 18);
+ ExpectFailure("optional_uint64: -5\n", "Expected integer, got: -", 1, 18);
+ ExpectFailure("optional_uint64: !\n", "Expected integer, got: !", 1, 18);
ExpectFailure("optional_uint64 {\n \n}\n", "Expected \":\", found \"{\".",
1, 17);
ExpectFailure("optional_uint32: 0x100000000\n",
- "Integer out of range.", 1, 18);
+ "Integer out of range (0x100000000)", 1, 18);
ExpectFailure("optional_uint64: 0x10000000000000000\n",
- "Integer out of range.", 1, 18);
+ "Integer out of range (0x10000000000000000)", 1, 18);
// Invalid values for a boolean field.
- ExpectFailure("optional_bool: \"hello\"\n", "Expected identifier.", 1, 16);
- ExpectFailure("optional_bool: 5\n", "Integer out of range.", 1, 16);
- ExpectFailure("optional_bool: -7.5\n", "Expected identifier.", 1, 16);
- ExpectFailure("optional_bool: !\n", "Expected identifier.", 1, 16);
+ ExpectFailure("optional_bool: \"hello\"\n",
+ "Expected identifier, got: \"hello\"", 1, 16);
+ ExpectFailure("optional_bool: 5\n", "Integer out of range (5)", 1, 16);
+ ExpectFailure("optional_bool: -7.5\n", "Expected identifier, got: -", 1, 16);
+ ExpectFailure("optional_bool: !\n", "Expected identifier, got: !", 1, 16);
ExpectFailure(
"optional_bool: meh\n",
@@ -1298,16 +1306,16 @@ TEST_F(TextFormatParserTest, InvalidFieldValues) {
1, 15);
// Invalid values for a string field.
- ExpectFailure("optional_string: true\n", "Expected string.", 1, 18);
- ExpectFailure("optional_string: 5\n", "Expected string.", 1, 18);
- ExpectFailure("optional_string: -7.5\n", "Expected string.", 1, 18);
- ExpectFailure("optional_string: !\n", "Expected string.", 1, 18);
+ ExpectFailure("optional_string: true\n", "Expected string, got: true", 1, 18);
+ ExpectFailure("optional_string: 5\n", "Expected string, got: 5", 1, 18);
+ ExpectFailure("optional_string: -7.5\n", "Expected string, got: -", 1, 18);
+ ExpectFailure("optional_string: !\n", "Expected string, got: !", 1, 18);
ExpectFailure("optional_string {\n \n}\n", "Expected \":\", found \"{\".",
1, 17);
// Invalid values for an enumeration field.
ExpectFailure("optional_nested_enum: \"hello\"\n",
- "Expected integer or identifier.", 1, 23);
+ "Expected integer or identifier, got: \"hello\"", 1, 23);
// Valid token, but enum value is not defined.
ExpectFailure("optional_nested_enum: 5\n",
@@ -1315,9 +1323,10 @@ TEST_F(TextFormatParserTest, InvalidFieldValues) {
"\"optional_nested_enum\".", 2, 1);
// We consume the negative sign, so the error position starts one character
// later.
- ExpectFailure("optional_nested_enum: -7.5\n", "Expected integer.", 1, 24);
+ ExpectFailure("optional_nested_enum: -7.5\n", "Expected integer, got: 7.5", 1,
+ 24);
ExpectFailure("optional_nested_enum: !\n",
- "Expected integer or identifier.", 1, 23);
+ "Expected integer or identifier, got: !", 1, 23);
ExpectFailure(
"optional_nested_enum: grah\n",
@@ -1340,7 +1349,7 @@ TEST_F(TextFormatParserTest, MessageDelimiters) {
// Unending message.
ExpectFailure("optional_nested_message {\n \nbb: 118\n",
- "Expected identifier.",
+ "Expected identifier, got: ",
4, 1);
}
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 7cdf5093..2ec4bc56 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -293,8 +293,8 @@ void Timestamp::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Timestamp)
}
-::google::protobuf::uint8* Timestamp::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Timestamp::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
// optional int64 seconds = 1;
if (this->seconds() != 0) {
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 7bf62597..19f4f86f 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -41,7 +41,7 @@ class Timestamp;
// ===================================================================
-class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Timestamp) */ {
public:
Timestamp();
virtual ~Timestamp();
@@ -80,7 +80,11 @@ class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 759cab27..f9182a75 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -548,8 +548,8 @@ void Type::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Type)
}
-::google::protobuf::uint8* Type::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Type::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -565,8 +565,8 @@ void Type::SerializeWithCachedSizes(
// repeated .google.protobuf.Field fields = 2;
for (unsigned int i = 0, n = this->fields_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->fields(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->fields(i), false, target);
}
// repeated string oneofs = 3;
@@ -582,15 +582,15 @@ void Type::SerializeWithCachedSizes(
// repeated .google.protobuf.Option options = 4;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 4, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 4, this->options(i), false, target);
}
// optional .google.protobuf.SourceContext source_context = 5;
if (this->has_source_context()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 5, *this->source_context_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 5, *this->source_context_, false, target);
}
// optional .google.protobuf.Syntax syntax = 6;
@@ -1417,8 +1417,8 @@ void Field::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Field)
}
-::google::protobuf::uint8* Field::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Field::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
// optional .google.protobuf.Field.Kind kind = 1;
if (this->kind() != 0) {
@@ -1472,8 +1472,8 @@ void Field::SerializeWithCachedSizes(
// repeated .google.protobuf.Option options = 9;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 9, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 9, this->options(i), false, target);
}
// optional string json_name = 10;
@@ -2192,8 +2192,8 @@ void Enum::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Enum)
}
-::google::protobuf::uint8* Enum::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Enum::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -2209,22 +2209,22 @@ void Enum::SerializeWithCachedSizes(
// repeated .google.protobuf.EnumValue enumvalue = 2;
for (unsigned int i = 0, n = this->enumvalue_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, this->enumvalue(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, this->enumvalue(i), false, target);
}
// repeated .google.protobuf.Option options = 3;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, this->options(i), false, target);
}
// optional .google.protobuf.SourceContext source_context = 4;
if (this->has_source_context()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 4, *this->source_context_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 4, *this->source_context_, false, target);
}
// optional .google.protobuf.Syntax syntax = 5;
@@ -2700,8 +2700,8 @@ void EnumValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.EnumValue)
}
-::google::protobuf::uint8* EnumValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -2722,8 +2722,8 @@ void EnumValue::SerializeWithCachedSizes(
// repeated .google.protobuf.Option options = 3;
for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 3, this->options(i), target);
+ InternalWriteMessageNoVirtualToArray(
+ 3, this->options(i), false, target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
@@ -3082,8 +3082,8 @@ void Option::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Option)
}
-::google::protobuf::uint8* Option::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Option::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
// optional string name = 1;
if (this->name().size() > 0) {
@@ -3099,8 +3099,8 @@ void Option::SerializeWithCachedSizes(
// optional .google.protobuf.Any value = 2;
if (this->has_value()) {
target = ::google::protobuf::internal::WireFormatLite::
- WriteMessageNoVirtualToArray(
- 2, *this->value_, target);
+ InternalWriteMessageNoVirtualToArray(
+ 2, *this->value_, false, target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 4255fa8c..ce29c281 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -130,7 +130,7 @@ inline bool Syntax_Parse(
}
// ===================================================================
-class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Type) */ {
public:
Type();
virtual ~Type();
@@ -164,7 +164,11 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -273,7 +277,7 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Field) */ {
public:
Field();
virtual ~Field();
@@ -307,7 +311,11 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -530,7 +538,7 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Enum) */ {
public:
Enum();
virtual ~Enum();
@@ -564,7 +572,11 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -656,7 +668,7 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValue) */ {
public:
EnumValue();
virtual ~EnumValue();
@@ -690,7 +702,11 @@ class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -759,7 +775,7 @@ class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Option) */ {
public:
Option();
virtual ~Option();
@@ -793,7 +809,11 @@ class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index da56ae0a..d5206d24 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -195,6 +195,7 @@ message TestDeprecatedFields {
// that.
message ForeignMessage {
optional int32 c = 1;
+ optional int32 d = 2;
}
enum ForeignEnum {
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index 4cc0e362..218447e9 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -69,6 +69,10 @@ extend google.protobuf.FieldOptions {
optional int32 field_opt2 = 7753913 [default=42];
}
+extend google.protobuf.OneofOptions {
+ optional int32 oneof_opt1 = 7740111;
+}
+
extend google.protobuf.EnumOptions {
optional sfixed32 enum_opt1 = 7753576;
}
@@ -100,6 +104,11 @@ message TestMessageWithCustomOptions {
optional string field1 = 1 [ctype=CORD,
(field_opt1)=8765432109];
+ oneof AnOneof {
+ option (oneof_opt1) = -99;
+ int32 oneof_field = 2;
+ }
+
enum AnEnum {
option (enum_opt1) = -789;
diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc
index 547c9fb5..409010a0 100644
--- a/src/google/protobuf/util/field_mask_util.cc
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -200,6 +200,15 @@ class FieldMaskTree {
MergeMessage(&root_, source, options, destination);
}
+ // Trims all fields not specified by this tree from the given message.
+ void TrimMessage(Message* message) {
+ // Do nothing if the tree is empty.
+ if (root_.children.empty()) {
+ return;
+ }
+ TrimMessage(&root_, message);
+ }
+
private:
struct Node {
Node() {}
@@ -233,6 +242,9 @@ class FieldMaskTree {
const FieldMaskUtil::MergeOptions& options,
Message* destination);
+ // Trims all fields not specified by this sub-tree from the given message.
+ void TrimMessage(const Node* node, Message* message);
+
Node root_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
@@ -367,11 +379,15 @@ void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
}
if (!field->is_repeated()) {
switch (field->cpp_type()) {
-#define COPY_VALUE(TYPE, Name) \
- case FieldDescriptor::CPPTYPE_##TYPE: { \
- destination_reflection->Set##Name( \
- destination, field, source_reflection->Get##Name(source, field)); \
- break; \
+#define COPY_VALUE(TYPE, Name) \
+ case FieldDescriptor::CPPTYPE_##TYPE: { \
+ if (source_reflection->HasField(source, field)) { \
+ destination_reflection->Set##Name( \
+ destination, field, source_reflection->Get##Name(source, field)); \
+ } else { \
+ destination_reflection->ClearField(destination, field); \
+ } \
+ break; \
}
COPY_VALUE(BOOL, Bool)
COPY_VALUE(INT32, Int32)
@@ -433,6 +449,26 @@ void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
}
}
+void FieldMaskTree::TrimMessage(const Node* node, Message* message) {
+ GOOGLE_DCHECK(!node->children.empty());
+ const Reflection* reflection = message->GetReflection();
+ const Descriptor* descriptor = message->GetDescriptor();
+ const int32 field_count = descriptor->field_count();
+ for (int index = 0; index < field_count; ++index) {
+ const FieldDescriptor* field = descriptor->field(index);
+ if (!ContainsKey(node->children, field->name())) {
+ reflection->ClearField(message, field);
+ } else {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ Node* child = node->children.at(field->name());
+ if (!child->children.empty()) {
+ TrimMessage(child, reflection->MutableMessage(message, field));
+ }
+ }
+ }
+ }
+}
+
} // namespace
void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
@@ -489,6 +525,14 @@ void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
tree.MergeMessage(source, options, destination);
}
+void FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* destination) {
+ // Build a FieldMaskTree and walk through the tree to merge all specified
+ // fields.
+ FieldMaskTree tree;
+ tree.MergeFromFieldMask(mask);
+ tree.TrimMessage(GOOGLE_CHECK_NOTNULL(destination));
+}
+
} // namespace util
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h
index 644161b9..e79b65e9 100644
--- a/src/google/protobuf/util/field_mask_util.h
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -107,10 +107,16 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
class MergeOptions;
- // Merges fields specified in a FieldMask into another message.
+ // Merges fields specified in a FieldMask into another message. See the
+ // comments in MergeOptions regarding compatibility with
+ // google/protobuf/field_mask.proto
static void MergeMessageTo(const Message& source, const FieldMask& mask,
const MergeOptions& options, Message* destination);
+ // Removes from 'message' any field that is not represented in the given
+ // FieldMask. If the FieldMask is empty, does nothing.
+ static void TrimMessage(const FieldMask& mask, Message* message);
+
private:
friend class SnakeCaseCamelCaseTest;
// Converts a field name from snake_case to camelCase:
@@ -148,6 +154,10 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil {
FieldMask* out);
};
+// Note that for compatibility with the defined behaviour for FieldMask in
+// google/protobuf/field_mask.proto, set replace_message_fields and
+// replace_repeated_fields to 'true'. The default options are not compatible
+// with google/protobuf/field_mask.proto.
class LIBPROTOBUF_EXPORT FieldMaskUtil::MergeOptions {
public:
MergeOptions()
diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc
index 9b7fb62a..43fb7905 100644
--- a/src/google/protobuf/util/field_mask_util_test.cc
+++ b/src/google/protobuf/util/field_mask_util_test.cc
@@ -349,6 +349,10 @@ TEST(FieldMaskUtilTest, MergeMessage) {
dst.Clear(); \
FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \
+ src.clear_##field_name(); \
+ tmp.clear_##field_name(); \
+ FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
+ EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \
}
TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int32)
TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int64)
@@ -484,6 +488,117 @@ TEST(FieldMaskUtilTest, MergeMessage) {
EXPECT_EQ(1234, nested_dst.payload().repeated_int32(0));
}
+TEST(FieldMaskUtilTest, TrimMessage) {
+#define TEST_TRIM_ONE_PRIMITIVE_FIELD(field_name) \
+ { \
+ TestAllTypes msg; \
+ TestUtil::SetAllFields(&msg); \
+ TestAllTypes tmp; \
+ tmp.set_##field_name(msg.field_name()); \
+ FieldMask mask; \
+ mask.add_paths(#field_name); \
+ FieldMaskUtil::TrimMessage(mask, &msg); \
+ EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+ }
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int32)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int64)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint32)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint64)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint32)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint64)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed32)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed64)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed32)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed64)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_float)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_double)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bool)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_string)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bytes)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_nested_enum)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_foreign_enum)
+ TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_import_enum)
+#undef TEST_TRIM_ONE_PRIMITIVE_FIELD
+
+#define TEST_TRIM_ONE_FIELD(field_name) \
+ { \
+ TestAllTypes msg; \
+ TestUtil::SetAllFields(&msg); \
+ TestAllTypes tmp; \
+ *tmp.mutable_##field_name() = msg.field_name(); \
+ FieldMask mask; \
+ mask.add_paths(#field_name); \
+ FieldMaskUtil::TrimMessage(mask, &msg); \
+ EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+ }
+ TEST_TRIM_ONE_FIELD(optional_nested_message)
+ TEST_TRIM_ONE_FIELD(optional_foreign_message)
+ TEST_TRIM_ONE_FIELD(optional_import_message)
+
+ TEST_TRIM_ONE_FIELD(repeated_int32)
+ TEST_TRIM_ONE_FIELD(repeated_int64)
+ TEST_TRIM_ONE_FIELD(repeated_uint32)
+ TEST_TRIM_ONE_FIELD(repeated_uint64)
+ TEST_TRIM_ONE_FIELD(repeated_sint32)
+ TEST_TRIM_ONE_FIELD(repeated_sint64)
+ TEST_TRIM_ONE_FIELD(repeated_fixed32)
+ TEST_TRIM_ONE_FIELD(repeated_fixed64)
+ TEST_TRIM_ONE_FIELD(repeated_sfixed32)
+ TEST_TRIM_ONE_FIELD(repeated_sfixed64)
+ TEST_TRIM_ONE_FIELD(repeated_float)
+ TEST_TRIM_ONE_FIELD(repeated_double)
+ TEST_TRIM_ONE_FIELD(repeated_bool)
+ TEST_TRIM_ONE_FIELD(repeated_string)
+ TEST_TRIM_ONE_FIELD(repeated_bytes)
+ TEST_TRIM_ONE_FIELD(repeated_nested_message)
+ TEST_TRIM_ONE_FIELD(repeated_foreign_message)
+ TEST_TRIM_ONE_FIELD(repeated_import_message)
+ TEST_TRIM_ONE_FIELD(repeated_nested_enum)
+ TEST_TRIM_ONE_FIELD(repeated_foreign_enum)
+ TEST_TRIM_ONE_FIELD(repeated_import_enum)
+#undef TEST_TRIM_ONE_FIELD
+
+ // Test trim nested fields.
+ NestedTestAllTypes nested_msg;
+ nested_msg.mutable_child()->mutable_payload()->set_optional_int32(1234);
+ nested_msg.mutable_child()
+ ->mutable_child()
+ ->mutable_payload()
+ ->set_optional_int32(5678);
+ NestedTestAllTypes trimmed_msg(nested_msg);
+ FieldMask mask;
+ FieldMaskUtil::FromString("child.payload", &mask);
+ FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+ EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+ EXPECT_EQ(0, trimmed_msg.child().child().payload().optional_int32());
+
+ trimmed_msg = nested_msg;
+ FieldMaskUtil::FromString("child.child.payload", &mask);
+ FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+ EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+ EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+ trimmed_msg = nested_msg;
+ FieldMaskUtil::FromString("child", &mask);
+ FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+ EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+ EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+ trimmed_msg = nested_msg;
+ FieldMaskUtil::FromString("child.child", &mask);
+ FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+ EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+ EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+ // Verify than an empty FieldMask trims nothing
+ TestAllTypes all_types_msg;
+ TestUtil::SetAllFields(&all_types_msg);
+ TestAllTypes trimmed_all_types(all_types_msg);
+ FieldMask empty_mask;
+ FieldMaskUtil::TrimMessage(empty_mask, &trimmed_all_types);
+ EXPECT_EQ(trimmed_all_types.DebugString(), all_types_msg.DebugString());
+}
+
} // namespace
} // namespace util
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index 72c0aca6..ef8da427 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -329,9 +329,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const {
// WebSafeBase64Escape does no padding by default.
WebSafeBase64Escape(*dest, &encoded);
// Remove trailing padding '=' characters before comparison.
- StringPiece src_no_padding(src, 0, src.ends_with("=")
- ? src.find_last_not_of('=') + 1
- : src.length());
+ StringPiece src_no_padding = StringPiece(src).substr(
+ 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length());
return encoded == src_no_padding;
}
return true;
@@ -343,9 +342,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const {
Base64Escape(
reinterpret_cast<const unsigned char*>(dest->data()), dest->length(),
&encoded, false);
- StringPiece src_no_padding(src, 0, src.ends_with("=")
- ? src.find_last_not_of('=') + 1
- : src.length());
+ StringPiece src_no_padding = StringPiece(src).substr(
+ 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length());
return encoded == src_no_padding;
}
return true;
@@ -354,6 +352,26 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const {
return false;
}
+void DataPiece::InternalCopy(const DataPiece& other) {
+ type_ = other.type_;
+ switch (type_) {
+ case TYPE_INT32:
+ case TYPE_INT64:
+ case TYPE_UINT32:
+ case TYPE_UINT64:
+ case TYPE_DOUBLE:
+ case TYPE_FLOAT:
+ case TYPE_BOOL:
+ case TYPE_ENUM:
+ case TYPE_NULL:
+ case TYPE_BYTES:
+ case TYPE_STRING: {
+ str_ = other.str_;
+ break;
+ }
+ }
+}
+
} // namespace converter
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index 8b2e35d3..e82cdbac 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -92,10 +92,11 @@ class LIBPROTOBUF_EXPORT DataPiece {
: type_(TYPE_BYTES),
str_(StringPiecePod::CreateFromStringPiece(value)),
use_strict_base64_decoding_(use_strict_base64_decoding) {}
- DataPiece(const DataPiece& r) : type_(r.type_), str_(r.str_) {}
+
+ DataPiece(const DataPiece& r) : type_(r.type_) { InternalCopy(r); }
+
DataPiece& operator=(const DataPiece& x) {
- type_ = x.type_;
- str_ = x.str_;
+ InternalCopy(x);
return *this;
}
@@ -171,6 +172,9 @@ class LIBPROTOBUF_EXPORT DataPiece {
// Decodes a base64 string. Returns true on success.
bool DecodeBase64(StringPiece src, string* dest) const;
+ // Helper function to initialize this DataPiece with 'other'.
+ void InternalCopy(const DataPiece& other);
+
// Data type for this piece of data.
Type type_;
diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc
index 24bd554e..06d2791b 100644
--- a/src/google/protobuf/util/internal/json_escaping.cc
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -255,7 +255,7 @@ StringPiece ToHex(uint16 cp, char* buffer) {
buffer[3] = kHex[cp & 0x0f];
cp >>= 4;
buffer[2] = kHex[cp & 0x0f];
- return StringPiece(buffer, 0, 6);
+ return StringPiece(buffer).substr(0, 6);
}
// Stores the 32-bit unicode code point as its hexadecimal digits in buffer
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
index 9f07363d..5781aa1e 100644
--- a/src/google/protobuf/util/internal/object_writer.h
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -101,6 +101,7 @@ class LIBPROTOBUF_EXPORT ObjectWriter {
// Renders a Null value.
virtual ObjectWriter* RenderNull(StringPiece name) = 0;
+
// Renders a DataPiece object to a ObjectWriter.
static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
ObjectWriter* ow);
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 36b79410..18cc1233 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -293,10 +293,14 @@ ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
ow_(enclosing),
parent_field_(NULL),
typeinfo_(typeinfo),
+ proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
type_(type),
- required_fields_(GetRequiredFields(type)),
size_index_(-1),
- array_index_(-1) {}
+ array_index_(-1) {
+ if (!proto3_) {
+ required_fields_ = GetRequiredFields(type_);
+ }
+}
ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
const google::protobuf::Field* field,
@@ -306,6 +310,7 @@ ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
ow_(this->parent()->ow_),
parent_field_(field),
typeinfo_(this->parent()->typeinfo_),
+ proto3_(this->parent()->proto3_),
type_(type),
size_index_(
!is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
@@ -316,12 +321,15 @@ ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
if (ow_->IsRepeated(*field)) {
// Update array_index_ if it is an explicit list.
if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
- } else {
+ } else if (!proto3_) {
+ // For required fields tracking.
this->parent()->RegisterField(field);
}
if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
- required_fields_ = GetRequiredFields(type_);
+ if (!proto3_) {
+ required_fields_ = GetRequiredFields(type_);
+ }
int start_pos = ow_->stream_->ByteCount();
// length of serialized message is the final buffer position minus
// starting buffer position, plus length adjustments for size fields
@@ -334,12 +342,14 @@ ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
}
ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
- // Calls the registered error listener for any required field(s) not yet
- // seen.
- for (set<const google::protobuf::Field*>::iterator it =
- required_fields_.begin();
- it != required_fields_.end(); ++it) {
- ow_->MissingField((*it)->name());
+ if (!proto3_) {
+ // Calls the registered error listener for any required field(s) not yet
+ // seen.
+ for (set<const google::protobuf::Field*>::iterator it =
+ required_fields_.begin();
+ it != required_fields_.end(); ++it) {
+ ow_->MissingField((*it)->name());
+ }
}
// Computes the total number of proto bytes used by a message, also adjusts
// the size of all parent messages by the length of this size field.
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
index 957565e7..ffb8f60e 100644
--- a/src/google/protobuf/util/internal/proto_writer.h
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -117,6 +117,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
return RenderDataPiece(name, DataPiece::NullData());
}
+
// Renders a DataPiece 'value' into a field whose wire type is determined
// from the given field 'name'.
virtual ProtoWriter* RenderDataPiece(StringPiece name,
@@ -198,6 +199,9 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
// TypeInfo to lookup types.
const TypeInfo* typeinfo_;
+ // Whether the root type is a proto3 or not.
+ bool proto3_;
+
// Additional variables if this element is a message:
// (Root element is always a message).
// type_ : the type of this element.
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 1f3781a4..0048d75b 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -121,7 +121,8 @@ ProtoStreamObjectSource::ProtoStreamObjectSource(
type_(type),
use_lower_camel_for_enums_(false),
recursion_depth_(0),
- max_recursion_depth_(kDefaultMaxRecursionDepth) {
+ max_recursion_depth_(kDefaultMaxRecursionDepth),
+ render_unknown_fields_(false) {
GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
}
@@ -134,7 +135,8 @@ ProtoStreamObjectSource::ProtoStreamObjectSource(
type_(type),
use_lower_camel_for_enums_(false),
recursion_depth_(0),
- max_recursion_depth_(kDefaultMaxRecursionDepth) {
+ max_recursion_depth_(kDefaultMaxRecursionDepth),
+ render_unknown_fields_(false) {
GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
}
@@ -184,6 +186,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
string field_name;
// last_tag set to dummy value that is different from tag.
uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
+ google::protobuf::UnknownFieldSet unknown_fields;
if (include_start_and_end) {
ow->StartObject(name);
@@ -199,7 +202,8 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
if (field == NULL) {
// If we didn't find a field, skip this unknown tag.
// TODO(wpoon): Check return boolean value.
- WireFormat::SkipField(stream_, tag, NULL);
+ WireFormat::SkipField(stream_, tag,
+ render_unknown_fields_ ? &unknown_fields : NULL);
tag = stream_->ReadTag();
continue;
}
@@ -221,6 +225,8 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
tag = stream_->ReadTag();
}
}
+
+
if (include_start_and_end) {
ow->EndObject();
}
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index d7d4347b..243f85b2 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -117,6 +117,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
max_recursion_depth_ = max_depth;
}
+
protected:
// Writes a proto2 Message to the ObjectWriter. When the given end_tag is
// found this method will complete, allowing it to be used for parsing both
@@ -287,6 +288,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
// Maximum allowed recursion depth.
int max_recursion_depth_;
+ // Whether to render unknown fields.
+ bool render_unknown_fields_;
+
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
};
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 97a7909a..8fa58a6f 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -384,6 +384,9 @@ ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
if (item_type_ == ANY) {
any_.reset(new AnyWriter(ow_));
}
+ if (item_type == MAP) {
+ map_keys_.reset(new hash_set<string>);
+ }
}
ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
@@ -398,11 +401,14 @@ ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
if (item_type == ANY) {
any_.reset(new AnyWriter(ow_));
}
+ if (item_type == MAP) {
+ map_keys_.reset(new hash_set<string>);
+ }
}
bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
StringPiece map_key) {
- return InsertIfNotPresent(&map_keys_, map_key.ToString());
+ return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
}
ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
@@ -1000,6 +1006,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
DataPiece(name, use_strict_base64_decoding()));
field = Lookup("value");
if (field == NULL) {
+ Pop();
GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
return this;
}
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index e1162d43..75e3d67d 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -231,7 +231,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
// Set of map keys already seen for the type_. Used to validate incoming
// messages so no map key appears more than once.
- hash_set<string> map_keys_;
+ google::protobuf::scoped_ptr<hash_set<string> > map_keys_;
// Conveys whether this Item is a placeholder or not. Placeholder items are
// pushed to stack to account for special types.
@@ -249,19 +249,19 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
strings::ByteSink* output, ErrorListener* listener);
// Returns true if the field is a map.
- bool IsMap(const google::protobuf::Field& field);
+ inline bool IsMap(const google::protobuf::Field& field);
// Returns true if the field is an any.
- bool IsAny(const google::protobuf::Field& field);
+ inline bool IsAny(const google::protobuf::Field& field);
// Returns true if the field is google.protobuf.Struct.
- bool IsStruct(const google::protobuf::Field& field);
+ inline bool IsStruct(const google::protobuf::Field& field);
// Returns true if the field is google.protobuf.Value.
- bool IsStructValue(const google::protobuf::Field& field);
+ inline bool IsStructValue(const google::protobuf::Field& field);
// Returns true if the field is google.protobuf.ListValue.
- bool IsStructListValue(const google::protobuf::Field& field);
+ inline bool IsStructListValue(const google::protobuf::Field& field);
// Renders google.protobuf.Value in struct.proto. It picks the right oneof
// type based on value's type.
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index ee7a51fc..5f613e77 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -52,7 +52,7 @@ const StringPiece SkipWhiteSpace(StringPiece str) {
for (i = 0; i < str.size() && isspace(str[i]); ++i) {
}
GOOGLE_DCHECK(i == str.size() || !isspace(str[i]));
- return StringPiece(str, i);
+ return str.substr(i);
}
} // namespace
@@ -128,8 +128,12 @@ string GetStringFromAny(const google::protobuf::Any& any) {
}
const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
- size_t idx = type_url.rfind('/');
- return type_url.substr(idx + 1);
+ if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
+ return type_url.substr(kTypeUrlSize + 1);
+ } else {
+ size_t idx = type_url.rfind('/');
+ return type_url.substr(idx + 1);
+ }
}
const string GetFullTypeWithUrl(StringPiece simple_type) {
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 33df8eda..26fed444 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -64,6 +64,10 @@ class EnumValue;
namespace protobuf {
namespace util {
namespace converter {
+
+// Size of "type.googleapis.com"
+static const int64 kTypeUrlSize = 19;
+
// Finds the tech option identified by option_name. Parses the boolean value and
// returns it.
// When the option with the given name is not found, default_value is returned.
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
index a1e24c18..3835b30e 100644
--- a/src/google/protobuf/util/json_format_proto3.proto
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -39,6 +39,7 @@ import "google/protobuf/wrappers.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/any.proto";
import "google/protobuf/field_mask.proto";
+import "google/protobuf/unittest.proto";
enum EnumType {
FOO = 0;
@@ -174,3 +175,7 @@ message TestBoolValue {
message TestCustomJsonName {
int32 value = 1 [json_name = "@value"];
}
+
+message TestExtensions {
+ .protobuf_unittest.TestAllExtensions extensions = 1;
+}
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index fe8119bf..fc55c2b9 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -474,7 +474,10 @@ bool MessageDifferencer::Compare(
// Retrieve all the set fields, including extensions.
vector<const FieldDescriptor*> message1_fields;
+ message1_fields.reserve(1 + message1.GetDescriptor()->field_count());
+
vector<const FieldDescriptor*> message2_fields;
+ message2_fields.reserve(1 + message2.GetDescriptor()->field_count());
reflection1->ListFields(message1, &message1_fields);
reflection2->ListFields(message2, &message2_fields);
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 3ea74e67..1abbfcba 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -570,6 +570,12 @@ class LIBPROTOBUF_EXPORT MessageDifferencer {
// any differences found in human-readable form to the supplied
// ZeroCopyOutputStream or Printer. If a printer is used, the delimiter
// *must* be '$'.
+ //
+ // WARNING: this reporter does not necessarily flush its output until it is
+ // destroyed. As a result, it is not safe to assume the output is valid or
+ // complete until after you destroy the reporter. For example, if you use a
+ // StreamReporter to write to a StringOutputStream, the target string may
+ // contain uninitialized data until the reporter is destroyed.
class LIBPROTOBUF_EXPORT StreamReporter : public Reporter {
public:
explicit StreamReporter(io::ZeroCopyOutputStream* output);
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 55fc7ecd..580d4db0 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -457,20 +457,48 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
INL static uint8* WriteBytesToArray(
field_number, const string& value, output);
- INL static uint8* WriteGroupToArray(
- field_number, const MessageLite& value, output);
- INL static uint8* WriteMessageToArray(
- field_number, const MessageLite& value, output);
+ // Whether to serialize deterministically (e.g., map keys are
+ // sorted) is a property of a CodedOutputStream, and in the process
+ // of serialization, the "ToArray" variants may be invoked. But they don't
+ // have a CodedOutputStream available, so they get an additional parameter
+ // telling them whether to serialize deterministically.
+ INL static uint8* InternalWriteGroupToArray(
+ field_number, const MessageLite& value, bool deterministic, output);
+ INL static uint8* InternalWriteMessageToArray(
+ field_number, const MessageLite& value, bool deterministic, output);
// Like above, but de-virtualize the call to SerializeWithCachedSizes(). The
// pointer must point at an instance of MessageType, *not* a subclass (or
// the subclass must not override SerializeWithCachedSizes()).
template<typename MessageType>
+ INL static uint8* InternalWriteGroupNoVirtualToArray(
+ field_number, const MessageType& value, bool deterministic, output);
+ template<typename MessageType>
+ INL static uint8* InternalWriteMessageNoVirtualToArray(
+ field_number, const MessageType& value, bool deterministic, output);
+
+ // For backward-compatibility, the last four methods also have versions
+ // that are non-deterministic always.
+ INL static uint8* WriteGroupToArray(
+ field_number, const MessageLite& value, output) {
+ return InternalWriteGroupToArray(field_number_arg, value, false, target);
+ }
+ INL static uint8* WriteMessageToArray(
+ field_number, const MessageLite& value, output) {
+ return InternalWriteMessageToArray(field_number_arg, value, false, target);
+ }
+ template<typename MessageType>
INL static uint8* WriteGroupNoVirtualToArray(
- field_number, const MessageType& value, output);
+ field_number, const MessageType& value, output) {
+ return InternalWriteGroupNoVirtualToArray(field_number_arg, value, false,
+ target);
+ }
template<typename MessageType>
INL static uint8* WriteMessageNoVirtualToArray(
- field_number, const MessageType& value, output);
+ field_number, const MessageType& value, output) {
+ return InternalWriteMessageNoVirtualToArray(field_number_arg, value, false,
+ target);
+ }
#undef output
#undef input
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 7bce21cf..ebd858ff 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -329,8 +329,8 @@ bool WireFormatLite::ReadRepeatedPrimitiveNoInline(
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
RepeatedField<CType>* values) {
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
+ int length;
+ if (!input->ReadVarintSizeAsInt(&length)) return false;
io::CodedInputStream::Limit limit = input->PushLimit(length);
while (input->BytesUntilLimit() > 0) {
CType value;
@@ -344,8 +344,8 @@ inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
io::CodedInputStream* input, RepeatedField<CType>* values) {
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
+ int length;
+ if (!input->ReadVarintSizeAsInt(&length)) return false;
const uint32 old_entries = values->size();
const uint32 new_entries = length / sizeof(CType);
const uint32 new_bytes = new_entries * sizeof(CType);
@@ -443,8 +443,8 @@ inline bool WireFormatLite::ReadGroup(int field_number,
}
inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input,
MessageLite* value) {
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
+ int length;
+ if (!input->ReadVarintSizeAsInt(&length)) return false;
std::pair<io::CodedInputStream::Limit, int> p =
input->IncrementRecursionDepthAndPushLimit(length);
if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
@@ -489,8 +489,8 @@ inline bool WireFormatLite::ReadGroupNoVirtualNoRecursionDepth(
template<typename MessageType_WorkAroundCppLookupDefect>
inline bool WireFormatLite::ReadMessageNoVirtual(
io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
- uint32 length;
- if (!input->ReadVarint32(&length)) return false;
+ int length;
+ if (!input->ReadVarintSizeAsInt(&length)) return false;
std::pair<io::CodedInputStream::Limit, int> p =
input->IncrementRecursionDepthAndPushLimit(length);
if (p.second < 0 || !value->
@@ -772,42 +772,40 @@ inline uint8* WireFormatLite::WriteBytesToArray(int field_number,
}
-inline uint8* WireFormatLite::WriteGroupToArray(int field_number,
- const MessageLite& value,
- uint8* target) {
+inline uint8* WireFormatLite::InternalWriteGroupToArray(
+ int field_number, const MessageLite& value, bool deterministic,
+ uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
- target = value.SerializeWithCachedSizesToArray(target);
+ target = value.InternalSerializeWithCachedSizesToArray(deterministic, target);
return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
}
-inline uint8* WireFormatLite::WriteMessageToArray(int field_number,
- const MessageLite& value,
- uint8* target) {
+inline uint8* WireFormatLite::InternalWriteMessageToArray(
+ int field_number, const MessageLite& value, bool deterministic,
+ uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
target = io::CodedOutputStream::WriteVarint32ToArray(
value.GetCachedSize(), target);
- return value.SerializeWithCachedSizesToArray(target);
+ return value.InternalSerializeWithCachedSizesToArray(deterministic, target);
}
// See comment on ReadGroupNoVirtual to understand the need for this template
// parameter name.
template<typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::WriteGroupNoVirtualToArray(
+inline uint8* WireFormatLite::InternalWriteGroupNoVirtualToArray(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
- uint8* target) {
+ bool deterministic, uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
- target = value.MessageType_WorkAroundCppLookupDefect
- ::SerializeWithCachedSizesToArray(target);
+ target = value.InternalSerializeWithCachedSizesToArray(deterministic, target);
return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
}
template<typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::WriteMessageNoVirtualToArray(
+inline uint8* WireFormatLite::InternalWriteMessageNoVirtualToArray(
int field_number, const MessageType_WorkAroundCppLookupDefect& value,
- uint8* target) {
+ bool deterministic, uint8* target) {
target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
target = io::CodedOutputStream::WriteVarint32ToArray(
value.MessageType_WorkAroundCppLookupDefect::GetCachedSize(), target);
- return value.MessageType_WorkAroundCppLookupDefect
- ::SerializeWithCachedSizesToArray(target);
+ return value.InternalSerializeWithCachedSizesToArray(deterministic, target);
}
// ===================================================================
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 60801423..08490f3f 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -448,8 +448,8 @@ void DoubleValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.DoubleValue)
}
-::google::protobuf::uint8* DoubleValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DoubleValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
// optional double value = 1;
if (this->value() != 0) {
@@ -706,8 +706,8 @@ void FloatValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.FloatValue)
}
-::google::protobuf::uint8* FloatValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FloatValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
// optional float value = 1;
if (this->value() != 0) {
@@ -964,8 +964,8 @@ void Int64Value::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Int64Value)
}
-::google::protobuf::uint8* Int64Value::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Int64Value::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
// optional int64 value = 1;
if (this->value() != 0) {
@@ -1224,8 +1224,8 @@ void UInt64Value::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.UInt64Value)
}
-::google::protobuf::uint8* UInt64Value::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UInt64Value::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
// optional uint64 value = 1;
if (this->value() != 0) {
@@ -1484,8 +1484,8 @@ void Int32Value::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.Int32Value)
}
-::google::protobuf::uint8* Int32Value::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Int32Value::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
// optional int32 value = 1;
if (this->value() != 0) {
@@ -1744,8 +1744,8 @@ void UInt32Value::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.UInt32Value)
}
-::google::protobuf::uint8* UInt32Value::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UInt32Value::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
// optional uint32 value = 1;
if (this->value() != 0) {
@@ -2004,8 +2004,8 @@ void BoolValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.BoolValue)
}
-::google::protobuf::uint8* BoolValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* BoolValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
// optional bool value = 1;
if (this->value() != 0) {
@@ -2271,8 +2271,8 @@ void StringValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.StringValue)
}
-::google::protobuf::uint8* StringValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* StringValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
// optional string value = 1;
if (this->value().size() > 0) {
@@ -2590,8 +2590,8 @@ void BytesValue::SerializeWithCachedSizes(
// @@protoc_insertion_point(serialize_end:google.protobuf.BytesValue)
}
-::google::protobuf::uint8* BytesValue::SerializeWithCachedSizesToArray(
- ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* BytesValue::InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
// optional bytes value = 1;
if (this->value().size() > 0) {
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 10784778..73f8ff62 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -49,7 +49,7 @@ class UInt64Value;
// ===================================================================
-class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DoubleValue) */ {
public:
DoubleValue();
virtual ~DoubleValue();
@@ -88,7 +88,11 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -140,7 +144,7 @@ class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FloatValue) */ {
public:
FloatValue();
virtual ~FloatValue();
@@ -179,7 +183,11 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -231,7 +239,7 @@ class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int64Value) */ {
public:
Int64Value();
virtual ~Int64Value();
@@ -270,7 +278,11 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -322,7 +334,7 @@ class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt64Value) */ {
public:
UInt64Value();
virtual ~UInt64Value();
@@ -361,7 +373,11 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -413,7 +429,7 @@ class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int32Value) */ {
public:
Int32Value();
virtual ~Int32Value();
@@ -452,7 +468,11 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -504,7 +524,7 @@ class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt32Value) */ {
public:
UInt32Value();
virtual ~UInt32Value();
@@ -543,7 +563,11 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -595,7 +619,7 @@ class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BoolValue) */ {
public:
BoolValue();
virtual ~BoolValue();
@@ -634,7 +658,11 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -686,7 +714,7 @@ class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.StringValue) */ {
public:
StringValue();
virtual ~StringValue();
@@ -725,7 +753,11 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
@@ -785,7 +817,7 @@ class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
};
// -------------------------------------------------------------------
-class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BytesValue) */ {
public:
BytesValue();
virtual ~BytesValue();
@@ -824,7 +856,11 @@ class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
- ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+ bool deterministic, ::google::protobuf::uint8* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+ return InternalSerializeWithCachedSizesToArray(false, output);
+ }
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();