4925 lines
207 KiB
Diff
4925 lines
207 KiB
Diff
From 11ceafebd2234b5c3e559f6ae3d433bf0ed7f667 Mon Sep 17 00:00:00 2001
|
|
From: chengzrz <czrzrichard@gmail.com>
|
|
Date: Mon, 17 Oct 2022 21:43:05 +0800
|
|
Subject: [PATCH] fix cve-2022-3171
|
|
|
|
Signed-off-by: chengzrz <czrzrichard@gmail.com>
|
|
---
|
|
.../com/google/protobuf/AbstractMessage.java | 27 +-
|
|
.../com/google/protobuf/ArrayDecoders.java | 146 +++---
|
|
.../com/google/protobuf/BinaryReader.java | 32 +-
|
|
.../protobuf/CodedInputStreamReader.java | 51 +-
|
|
.../DescriptorMessageInfoFactory.java | 4 +-
|
|
.../com/google/protobuf/DynamicMessage.java | 5 +-
|
|
.../com/google/protobuf/ExtensionSchema.java | 1 +
|
|
.../google/protobuf/ExtensionSchemaFull.java | 5 +-
|
|
.../google/protobuf/ExtensionSchemaLite.java | 52 +-
|
|
.../java/com/google/protobuf/FieldSet.java | 63 ++-
|
|
.../google/protobuf/GeneratedMessageLite.java | 169 ++++--
|
|
.../google/protobuf/GeneratedMessageV3.java | 110 +++-
|
|
.../google/protobuf/MessageLiteToString.java | 117 +++--
|
|
.../google/protobuf/MessageReflection.java | 439 +++++++++++++++-
|
|
.../com/google/protobuf/MessageSchema.java | 485 +++++++++++-------
|
|
.../com/google/protobuf/MessageSetSchema.java | 17 +-
|
|
.../protobuf/NewInstanceSchemaLite.java | 5 +-
|
|
.../main/java/com/google/protobuf/Reader.java | 8 +
|
|
.../java/com/google/protobuf/SchemaUtil.java | 30 +-
|
|
.../java/com/google/protobuf/TextFormat.java | 2 +-
|
|
.../google/protobuf/UnknownFieldSetLite.java | 38 +-
|
|
.../protobuf/UnknownFieldSetLiteSchema.java | 12 +-
|
|
.../java/com/google/protobuf/LiteTest.java | 36 +-
|
|
.../google/protobuf/util/FieldMaskTree.java | 10 +-
|
|
.../protobuf/compiler/java/java_enum_field.cc | 94 ++--
|
|
.../protobuf/compiler/java/java_enum_field.h | 94 ++--
|
|
.../protobuf/compiler/java/java_field.cc | 4 +-
|
|
.../protobuf/compiler/java/java_field.h | 5 +-
|
|
.../protobuf/compiler/java/java_map_field.cc | 30 +-
|
|
.../protobuf/compiler/java/java_map_field.h | 34 +-
|
|
.../protobuf/compiler/java/java_message.cc | 220 ++------
|
|
.../compiler/java/java_message_builder.cc | 163 ++++--
|
|
.../compiler/java/java_message_builder.h | 5 +
|
|
.../compiler/java/java_message_field.cc | 126 ++---
|
|
.../compiler/java/java_message_field.h | 87 ++--
|
|
.../compiler/java/java_primitive_field.cc | 66 +--
|
|
.../compiler/java/java_primitive_field.h | 90 ++--
|
|
.../compiler/java/java_string_field.cc | 59 +--
|
|
.../compiler/java/java_string_field.h | 87 ++--
|
|
39 files changed, 1907 insertions(+), 1121 deletions(-)
|
|
|
|
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 1364fce..ebf4318 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
|
|
@@ -426,27 +426,22 @@ public abstract class AbstractMessage
|
|
throws IOException {
|
|
boolean discardUnknown = input.shouldDiscardUnknownFields();
|
|
final UnknownFieldSet.Builder unknownFields =
|
|
- discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
|
|
- while (true) {
|
|
- final int tag = input.readTag();
|
|
- if (tag == 0) {
|
|
- break;
|
|
- }
|
|
-
|
|
- MessageReflection.BuilderAdapter builderAdapter =
|
|
- new MessageReflection.BuilderAdapter(this);
|
|
- if (!MessageReflection.mergeFieldFrom(
|
|
- input, unknownFields, extensionRegistry, getDescriptorForType(), builderAdapter, tag)) {
|
|
- // end group tag
|
|
- break;
|
|
- }
|
|
- }
|
|
+ discardUnknown ? null : getUnknownFieldSetBuilder();
|
|
+ MessageReflection.mergeMessageFrom(this, unknownFields, input, extensionRegistry);
|
|
if (unknownFields != null) {
|
|
- setUnknownFields(unknownFields.build());
|
|
+ setUnknownFieldSetBuilder(unknownFields);
|
|
}
|
|
return (BuilderType) this;
|
|
}
|
|
|
|
+ protected UnknownFieldSet.Builder getUnknownFieldSetBuilder() {
|
|
+ return UnknownFieldSet.newBuilder(getUnknownFields());
|
|
+ }
|
|
+
|
|
+ protected void setUnknownFieldSetBuilder(final UnknownFieldSet.Builder builder) {
|
|
+ setUnknownFields(builder.build());
|
|
+ }
|
|
+
|
|
@Override
|
|
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
|
|
setUnknownFields(
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
|
|
index 1217e11..39b7927 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
|
|
@@ -234,6 +234,29 @@ final class ArrayDecoders {
|
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
static int decodeMessageField(
|
|
Schema schema, byte[] data, int position, int limit, Registers registers) throws IOException {
|
|
+ Object msg = schema.newInstance();
|
|
+ int offset = mergeMessageField(msg, schema, data, position, limit, registers);
|
|
+ schema.makeImmutable(msg);
|
|
+ registers.object1 = msg;
|
|
+ return offset;
|
|
+ }
|
|
+
|
|
+ /** Decodes a group value. */
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
+ static int decodeGroupField(
|
|
+ Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers)
|
|
+ throws IOException {
|
|
+ Object msg = schema.newInstance();
|
|
+ int offset = mergeGroupField(msg, schema, data, position, limit, endGroup, registers);
|
|
+ schema.makeImmutable(msg);
|
|
+ registers.object1 = msg;
|
|
+ return offset;
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
+ static int mergeMessageField(
|
|
+ Object msg, Schema schema, byte[] data, int position, int limit, Registers registers)
|
|
+ throws IOException {
|
|
int length = data[position++];
|
|
if (length < 0) {
|
|
position = decodeVarint32(length, data, position, registers);
|
|
@@ -242,27 +265,28 @@ final class ArrayDecoders {
|
|
if (length < 0 || length > limit - position) {
|
|
throw InvalidProtocolBufferException.truncatedMessage();
|
|
}
|
|
- Object result = schema.newInstance();
|
|
- schema.mergeFrom(result, data, position, position + length, registers);
|
|
- schema.makeImmutable(result);
|
|
- registers.object1 = result;
|
|
+ schema.mergeFrom(msg, data, position, position + length, registers);
|
|
+ registers.object1 = msg;
|
|
return position + length;
|
|
}
|
|
|
|
- /** Decodes a group value. */
|
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
- static int decodeGroupField(
|
|
- Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers)
|
|
+ static int mergeGroupField(
|
|
+ Object msg,
|
|
+ Schema schema,
|
|
+ byte[] data,
|
|
+ int position,
|
|
+ int limit,
|
|
+ int endGroup,
|
|
+ Registers registers)
|
|
throws IOException {
|
|
// A group field must has a MessageSchema (the only other subclass of Schema is MessageSetSchema
|
|
// and it can't be used in group fields).
|
|
final MessageSchema messageSchema = (MessageSchema) schema;
|
|
- Object result = messageSchema.newInstance();
|
|
// It's OK to directly use parseProto2Message since proto3 doesn't have group.
|
|
final int endPosition =
|
|
- messageSchema.parseProto2Message(result, data, position, limit, endGroup, registers);
|
|
- messageSchema.makeImmutable(result);
|
|
- registers.object1 = result;
|
|
+ messageSchema.parseProto2Message(msg, data, position, limit, endGroup, registers);
|
|
+ registers.object1 = msg;
|
|
return endPosition;
|
|
}
|
|
|
|
@@ -847,26 +871,19 @@ final class ArrayDecoders {
|
|
break;
|
|
}
|
|
case ENUM:
|
|
- {
|
|
- IntArrayList list = new IntArrayList();
|
|
- position = decodePackedVarint32List(data, position, list, registers);
|
|
- UnknownFieldSetLite unknownFields = message.unknownFields;
|
|
- if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
|
- unknownFields = null;
|
|
- }
|
|
- unknownFields =
|
|
- SchemaUtil.filterUnknownEnumList(
|
|
- fieldNumber,
|
|
- list,
|
|
- extension.descriptor.getEnumType(),
|
|
- unknownFields,
|
|
- unknownFieldSchema);
|
|
- if (unknownFields != null) {
|
|
- message.unknownFields = unknownFields;
|
|
+ {
|
|
+ IntArrayList list = new IntArrayList();
|
|
+ position = decodePackedVarint32List(data, position, list, registers);
|
|
+ SchemaUtil.filterUnknownEnumList(
|
|
+ message,
|
|
+ fieldNumber,
|
|
+ list,
|
|
+ extension.descriptor.getEnumType(),
|
|
+ null,
|
|
+ unknownFieldSchema);
|
|
+ extensions.setField(extension.descriptor, list);
|
|
+ break;
|
|
}
|
|
- extensions.setField(extension.descriptor, list);
|
|
- break;
|
|
- }
|
|
default:
|
|
throw new IllegalStateException(
|
|
"Type cannot be packed: " + extension.descriptor.getLiteType());
|
|
@@ -878,13 +895,8 @@ final class ArrayDecoders {
|
|
position = decodeVarint32(data, position, registers);
|
|
Object enumValue = extension.descriptor.getEnumType().findValueByNumber(registers.int1);
|
|
if (enumValue == null) {
|
|
- UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
|
|
- if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
|
- unknownFields = UnknownFieldSetLite.newInstance();
|
|
- ((GeneratedMessageLite) message).unknownFields = unknownFields;
|
|
- }
|
|
SchemaUtil.storeUnknownEnum(
|
|
- fieldNumber, registers.int1, unknownFields, unknownFieldSchema);
|
|
+ message, fieldNumber, registers.int1, null, unknownFieldSchema);
|
|
return position;
|
|
}
|
|
// Note, we store the integer value instead of the actual enum object in FieldSet.
|
|
@@ -941,20 +953,45 @@ final class ArrayDecoders {
|
|
value = registers.object1;
|
|
break;
|
|
case GROUP:
|
|
- final int endTag = (fieldNumber << 3) | WireFormat.WIRETYPE_END_GROUP;
|
|
- position = decodeGroupField(
|
|
- Protobuf.getInstance().schemaFor(extension.getMessageDefaultInstance().getClass()),
|
|
- data, position, limit, endTag, registers);
|
|
- value = registers.object1;
|
|
- break;
|
|
-
|
|
+ {
|
|
+ final int endTag = (fieldNumber << 3) | WireFormat.WIRETYPE_END_GROUP;
|
|
+ final Schema fieldSchema =
|
|
+ Protobuf.getInstance()
|
|
+ .schemaFor(extension.getMessageDefaultInstance().getClass());
|
|
+ if (extension.isRepeated()) {
|
|
+ position = decodeGroupField(fieldSchema, data, position, limit, endTag, registers);
|
|
+ extensions.addRepeatedField(extension.descriptor, registers.object1);
|
|
+ } else {
|
|
+ Object oldValue = extensions.getField(extension.descriptor);
|
|
+ if (oldValue == null) {
|
|
+ oldValue = fieldSchema.newInstance();
|
|
+ extensions.setField(extension.descriptor, oldValue);
|
|
+ }
|
|
+ position =
|
|
+ mergeGroupField(
|
|
+ oldValue, fieldSchema, data, position, limit, endTag, registers);
|
|
+ }
|
|
+ return position;
|
|
+ }
|
|
case MESSAGE:
|
|
- position = decodeMessageField(
|
|
- Protobuf.getInstance().schemaFor(extension.getMessageDefaultInstance().getClass()),
|
|
- data, position, limit, registers);
|
|
- value = registers.object1;
|
|
- break;
|
|
-
|
|
+ {
|
|
+ final Schema fieldSchema =
|
|
+ Protobuf.getInstance()
|
|
+ .schemaFor(extension.getMessageDefaultInstance().getClass());
|
|
+ if (extension.isRepeated()) {
|
|
+ position = decodeMessageField(fieldSchema, data, position, limit, registers);
|
|
+ extensions.addRepeatedField(extension.descriptor, registers.object1);
|
|
+ } else {
|
|
+ Object oldValue = extensions.getField(extension.descriptor);
|
|
+ if (oldValue == null) {
|
|
+ oldValue = fieldSchema.newInstance();
|
|
+ extensions.setField(extension.descriptor, oldValue);
|
|
+ }
|
|
+ position =
|
|
+ mergeMessageField(oldValue, fieldSchema, data, position, limit, registers);
|
|
+ }
|
|
+ return position;
|
|
+ }
|
|
case ENUM:
|
|
throw new IllegalStateException("Shouldn't reach here.");
|
|
}
|
|
@@ -962,17 +999,6 @@ final class ArrayDecoders {
|
|
if (extension.isRepeated()) {
|
|
extensions.addRepeatedField(extension.descriptor, value);
|
|
} else {
|
|
- switch (extension.getLiteType()) {
|
|
- case MESSAGE:
|
|
- case GROUP:
|
|
- Object oldValue = extensions.getField(extension.descriptor);
|
|
- if (oldValue != null) {
|
|
- value = Internal.mergeMessage(oldValue, value);
|
|
- }
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
extensions.setField(extension.descriptor, value);
|
|
}
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/BinaryReader.java b/java/core/src/main/java/com/google/protobuf/BinaryReader.java
|
|
index d64574c..3a0e04d 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/BinaryReader.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/BinaryReader.java
|
|
@@ -247,6 +247,15 @@ abstract class BinaryReader implements Reader {
|
|
|
|
private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
throws IOException {
|
|
+ T newInstance = schema.newInstance();
|
|
+ mergeMessageField(newInstance, schema, extensionRegistry);
|
|
+ schema.makeImmutable(newInstance);
|
|
+ return newInstance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> void mergeMessageField(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
int size = readVarint32();
|
|
requireBytes(size);
|
|
|
|
@@ -256,15 +265,10 @@ abstract class BinaryReader implements Reader {
|
|
limit = newLimit;
|
|
|
|
try {
|
|
- // Allocate and read the message.
|
|
- T message = schema.newInstance();
|
|
- schema.mergeFrom(message, this, extensionRegistry);
|
|
- schema.makeImmutable(message);
|
|
-
|
|
+ schema.mergeFrom(target, this, extensionRegistry);
|
|
if (pos != newLimit) {
|
|
throw InvalidProtocolBufferException.parseFailure();
|
|
}
|
|
- return message;
|
|
} finally {
|
|
// Restore the limit.
|
|
limit = prevLimit;
|
|
@@ -287,19 +291,23 @@ abstract class BinaryReader implements Reader {
|
|
|
|
private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
throws IOException {
|
|
+ T newInstance = schema.newInstance();
|
|
+ mergeGroupField(newInstance, schema, extensionRegistry);
|
|
+ schema.makeImmutable(newInstance);
|
|
+ return newInstance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> void mergeGroupField(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
int prevEndGroupTag = endGroupTag;
|
|
endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP);
|
|
|
|
try {
|
|
- // Allocate and read the message.
|
|
- T message = schema.newInstance();
|
|
- schema.mergeFrom(message, this, extensionRegistry);
|
|
- schema.makeImmutable(message);
|
|
-
|
|
+ schema.mergeFrom(target, this, extensionRegistry);
|
|
if (tag != endGroupTag) {
|
|
throw InvalidProtocolBufferException.parseFailure();
|
|
}
|
|
- return message;
|
|
} finally {
|
|
// Restore the old end group tag.
|
|
endGroupTag = prevEndGroupTag;
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
|
|
index 7658f62..1d992d7 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
|
|
@@ -197,9 +197,15 @@ final class CodedInputStreamReader implements Reader {
|
|
return readGroup(schema, extensionRegistry);
|
|
}
|
|
|
|
- // Should have the same semantics of CodedInputStream#readMessage()
|
|
- private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
- throws IOException {
|
|
+ @Override
|
|
+ public <T> void mergeMessageField(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
+ requireWireType(WIRETYPE_LENGTH_DELIMITED);
|
|
+ mergeMessageFieldInternal(target, schema, extensionRegistry);
|
|
+ }
|
|
+
|
|
+ private <T> void mergeMessageFieldInternal(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
int size = input.readUInt32();
|
|
if (input.recursionDepth >= input.recursionLimit) {
|
|
throw InvalidProtocolBufferException.recursionLimitExceeded();
|
|
@@ -207,39 +213,54 @@ final class CodedInputStreamReader implements Reader {
|
|
|
|
// Push the new limit.
|
|
final int prevLimit = input.pushLimit(size);
|
|
- // Allocate and read the message.
|
|
- T message = schema.newInstance();
|
|
++input.recursionDepth;
|
|
- schema.mergeFrom(message, this, extensionRegistry);
|
|
- schema.makeImmutable(message);
|
|
+ schema.mergeFrom(target, this, extensionRegistry);
|
|
input.checkLastTagWas(0);
|
|
--input.recursionDepth;
|
|
// Restore the previous limit.
|
|
input.popLimit(prevLimit);
|
|
- return message;
|
|
}
|
|
|
|
- private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
+ // Should have the same semantics of CodedInputStream#readMessage()
|
|
+ private <T> T readMessage(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
throws IOException {
|
|
+ T newInstance = schema.newInstance();
|
|
+ mergeMessageFieldInternal(newInstance, schema, extensionRegistry);
|
|
+ schema.makeImmutable(newInstance);
|
|
+ return newInstance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> void mergeGroupField(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
+ requireWireType(WIRETYPE_START_GROUP);
|
|
+ mergeGroupFieldInternal(target, schema, extensionRegistry);
|
|
+ }
|
|
+
|
|
+ private <T> void mergeGroupFieldInternal(
|
|
+ T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
|
|
int prevEndGroupTag = endGroupTag;
|
|
endGroupTag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WIRETYPE_END_GROUP);
|
|
|
|
try {
|
|
- // Allocate and read the message.
|
|
- T message = schema.newInstance();
|
|
- schema.mergeFrom(message, this, extensionRegistry);
|
|
- schema.makeImmutable(message);
|
|
-
|
|
+ schema.mergeFrom(target, this, extensionRegistry);
|
|
if (tag != endGroupTag) {
|
|
throw InvalidProtocolBufferException.parseFailure();
|
|
}
|
|
- return message;
|
|
} finally {
|
|
// Restore the old end group tag.
|
|
endGroupTag = prevEndGroupTag;
|
|
}
|
|
}
|
|
|
|
+ private <T> T readGroup(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
+ throws IOException {
|
|
+ T newInstance = schema.newInstance();
|
|
+ mergeGroupFieldInternal(newInstance, schema, extensionRegistry);
|
|
+ schema.makeImmutable(newInstance);
|
|
+ return newInstance;
|
|
+ }
|
|
+
|
|
@Override
|
|
public ByteString readBytes() throws IOException {
|
|
requireWireType(WIRETYPE_LENGTH_DELIMITED);
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
|
|
index 7975136..21ded52 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
|
|
@@ -402,8 +402,8 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory {
|
|
boolean enforceUtf8 = true;
|
|
for (int i = 0; i < fieldDescriptors.size(); ++i) {
|
|
FieldDescriptor fd = fieldDescriptors.get(i);
|
|
- if (fd.getContainingOneof() != null) {
|
|
- // Build a oneof member field.
|
|
+ if (fd.getContainingOneof() != null && !fd.getContainingOneof().isSynthetic()) {
|
|
+ // Build a oneof member field. But only if it is a real oneof, not a proto3 optional
|
|
builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, null));
|
|
continue;
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
|
|
index 8beebba..51e6b0c 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
|
|
@@ -421,7 +421,10 @@ public final class DynamicMessage extends AbstractMessage {
|
|
fields.makeImmutable();
|
|
DynamicMessage result =
|
|
new DynamicMessage(
|
|
- type, fields, java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
|
|
+ type,
|
|
+ fields,
|
|
+ java.util.Arrays.copyOf(oneofCases, oneofCases.length),
|
|
+ unknownFields);
|
|
return result;
|
|
}
|
|
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
|
|
index 2eae22d..bd391a2 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
|
|
@@ -59,6 +59,7 @@ abstract class ExtensionSchema<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
* or UnknownFieldSetLite in lite runtime.
|
|
*/
|
|
abstract <UT, UB> UB parseExtension(
|
|
+ Object containerMessage,
|
|
Reader reader,
|
|
Object extension,
|
|
ExtensionRegistryLite extensionRegistry,
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
|
|
index 9055851..9376e87 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
|
|
@@ -85,6 +85,7 @@ final class ExtensionSchemaFull extends ExtensionSchema<FieldDescriptor> {
|
|
|
|
@Override
|
|
<UT, UB> UB parseExtension(
|
|
+ Object containerMessage,
|
|
Reader reader,
|
|
Object extensionObject,
|
|
ExtensionRegistryLite extensionRegistry,
|
|
@@ -202,7 +203,7 @@ final class ExtensionSchemaFull extends ExtensionSchema<FieldDescriptor> {
|
|
} else {
|
|
unknownFields =
|
|
SchemaUtil.storeUnknownEnum(
|
|
- fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
+ containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
}
|
|
}
|
|
value = enumList;
|
|
@@ -221,7 +222,7 @@ final class ExtensionSchemaFull extends ExtensionSchema<FieldDescriptor> {
|
|
Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number);
|
|
if (enumValue == null) {
|
|
return SchemaUtil.storeUnknownEnum(
|
|
- fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
+ containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
}
|
|
value = enumValue;
|
|
} else {
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
|
|
index 437cca2..7e20ed2 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
|
|
@@ -32,7 +32,6 @@ package com.google.protobuf;
|
|
|
|
import com.google.protobuf.GeneratedMessageLite.ExtensionDescriptor;
|
|
import java.io.IOException;
|
|
-import java.nio.ByteBuffer;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
@@ -67,6 +66,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
|
|
@Override
|
|
<UT, UB> UB parseExtension(
|
|
+ Object containerMessage,
|
|
Reader reader,
|
|
Object extensionObject,
|
|
ExtensionRegistryLite extensionRegistry,
|
|
@@ -178,6 +178,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
reader.readEnumList(list);
|
|
unknownFields =
|
|
SchemaUtil.filterUnknownEnumList(
|
|
+ containerMessage,
|
|
fieldNumber,
|
|
list,
|
|
extension.descriptor.getEnumType(),
|
|
@@ -199,7 +200,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number);
|
|
if (enumValue == null) {
|
|
return SchemaUtil.storeUnknownEnum(
|
|
- fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
+ containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
|
}
|
|
// Note, we store the integer value instead of the actual enum object in FieldSet.
|
|
// This is also different from full-runtime where we store EnumValueDescriptor.
|
|
@@ -253,12 +254,46 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
value = reader.readString();
|
|
break;
|
|
case GROUP:
|
|
+ // Special case handling for non-repeated sub-messages: merge in-place rather than
|
|
+ // building up new sub-messages and merging those, which is too slow.
|
|
+ // TODO(b/249368670): clean this up
|
|
+ if (!extension.isRepeated()) {
|
|
+ Object oldValue = extensions.getField(extension.descriptor);
|
|
+ if (oldValue instanceof GeneratedMessageLite) {
|
|
+ Schema extSchema = Protobuf.getInstance().schemaFor(oldValue);
|
|
+ if (!((GeneratedMessageLite<?, ?>) oldValue).isMutable()) {
|
|
+ Object newValue = extSchema.newInstance();
|
|
+ extSchema.mergeFrom(newValue, oldValue);
|
|
+ extensions.setField(extension.descriptor, newValue);
|
|
+ oldValue = newValue;
|
|
+ }
|
|
+ reader.mergeGroupField(oldValue, extSchema, extensionRegistry);
|
|
+ return unknownFields;
|
|
+ }
|
|
+ }
|
|
value =
|
|
reader.readGroup(
|
|
extension.getMessageDefaultInstance().getClass(), extensionRegistry);
|
|
break;
|
|
|
|
case MESSAGE:
|
|
+ // Special case handling for non-repeated sub-messages: merge in-place rather than
|
|
+ // building up new sub-messages and merging those, which is too slow.
|
|
+ // TODO(b/249368670): clean this up
|
|
+ if (!extension.isRepeated()) {
|
|
+ Object oldValue = extensions.getField(extension.descriptor);
|
|
+ if (oldValue instanceof GeneratedMessageLite) {
|
|
+ Schema extSchema = Protobuf.getInstance().schemaFor(oldValue);
|
|
+ if (!((GeneratedMessageLite<?, ?>) oldValue).isMutable()) {
|
|
+ Object newValue = extSchema.newInstance();
|
|
+ extSchema.mergeFrom(newValue, oldValue);
|
|
+ extensions.setField(extension.descriptor, newValue);
|
|
+ oldValue = newValue;
|
|
+ }
|
|
+ reader.mergeMessageField(oldValue, extSchema, extensionRegistry);
|
|
+ return unknownFields;
|
|
+ }
|
|
+ }
|
|
value =
|
|
reader.readMessage(
|
|
extension.getMessageDefaultInstance().getClass(), extensionRegistry);
|
|
@@ -274,6 +309,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
switch (extension.getLiteType()) {
|
|
case MESSAGE:
|
|
case GROUP:
|
|
+ // TODO(b/249368670): this shouldn't be reachable, clean this up
|
|
Object oldValue = extensions.getField(extension.descriptor);
|
|
if (oldValue != null) {
|
|
value = Internal.mergeMessage(oldValue, value);
|
|
@@ -527,15 +563,13 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
|
throws IOException {
|
|
GeneratedMessageLite.GeneratedExtension<?, ?> extension =
|
|
(GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject;
|
|
- Object value = extension.getMessageDefaultInstance().newBuilderForType().buildPartial();
|
|
|
|
- Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(data.toByteArray()), true);
|
|
+ MessageLite.Builder builder = extension.getMessageDefaultInstance().newBuilderForType();
|
|
|
|
- Protobuf.getInstance().mergeFrom(value, reader, extensionRegistry);
|
|
- extensions.setField(extension.descriptor, value);
|
|
+ final CodedInputStream input = data.newCodedInput();
|
|
|
|
- if (reader.getFieldNumber() != Reader.READ_DONE) {
|
|
- throw InvalidProtocolBufferException.invalidEndTag();
|
|
- }
|
|
+ builder.mergeFrom(input, extensionRegistry);
|
|
+ extensions.setField(extension.descriptor, builder.buildPartial());
|
|
+ input.checkLastTagWas(0);
|
|
}
|
|
}
|
|
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 d52aede..e30cf90 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
|
|
@@ -39,6 +39,7 @@ import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
+import java.util.Map.Entry;
|
|
|
|
/**
|
|
* A class which represents an arbitrary set of fields of some message type. This is used to
|
|
@@ -124,6 +125,12 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
if (isImmutable) {
|
|
return;
|
|
}
|
|
+ for (int i = 0; i < fields.getNumArrayEntries(); ++i) {
|
|
+ Entry<T, Object> entry = fields.getArrayEntryAt(i);
|
|
+ if (entry.getValue() instanceof GeneratedMessageLite) {
|
|
+ ((GeneratedMessageLite<?, ?>) entry.getValue()).makeImmutable();
|
|
+ }
|
|
+ }
|
|
fields.makeImmutable();
|
|
isImmutable = true;
|
|
}
|
|
@@ -933,8 +940,27 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
this.isMutable = true;
|
|
}
|
|
|
|
- /** Creates the FieldSet */
|
|
+ /**
|
|
+ * Creates the FieldSet
|
|
+ *
|
|
+ * @throws UninitializedMessageException if a message field is missing required fields.
|
|
+ */
|
|
public FieldSet<T> build() {
|
|
+ return buildImpl(false);
|
|
+ }
|
|
+
|
|
+ /** Creates the FieldSet but does not validate that all required fields are present. */
|
|
+ public FieldSet<T> buildPartial() {
|
|
+ return buildImpl(true);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates the FieldSet.
|
|
+ *
|
|
+ * @param partial controls whether to do a build() or buildPartial() when converting submessage
|
|
+ * builders to messages.
|
|
+ */
|
|
+ private FieldSet<T> buildImpl(boolean partial) {
|
|
if (fields.isEmpty()) {
|
|
return FieldSet.emptySet();
|
|
}
|
|
@@ -943,7 +969,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
if (hasNestedBuilders) {
|
|
// Make a copy of the fields map with all Builders replaced by Message.
|
|
fieldsForBuild = cloneAllFieldsMap(fields, /* copyList */ false);
|
|
- replaceBuilders(fieldsForBuild);
|
|
+ replaceBuilders(fieldsForBuild, partial);
|
|
}
|
|
FieldSet<T> fieldSet = new FieldSet<>(fieldsForBuild);
|
|
fieldSet.hasLazyField = hasLazyField;
|
|
@@ -951,22 +977,22 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
}
|
|
|
|
private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
|
|
- SmallSortedMap<T, Object> fieldMap) {
|
|
+ SmallSortedMap<T, Object> fieldMap, boolean partial) {
|
|
for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
|
|
- replaceBuilders(fieldMap.getArrayEntryAt(i));
|
|
+ replaceBuilders(fieldMap.getArrayEntryAt(i), partial);
|
|
}
|
|
for (Map.Entry<T, Object> entry : fieldMap.getOverflowEntries()) {
|
|
- replaceBuilders(entry);
|
|
+ replaceBuilders(entry, partial);
|
|
}
|
|
}
|
|
|
|
private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
|
|
- Map.Entry<T, Object> entry) {
|
|
- entry.setValue(replaceBuilders(entry.getKey(), entry.getValue()));
|
|
+ Map.Entry<T, Object> entry, boolean partial) {
|
|
+ entry.setValue(replaceBuilders(entry.getKey(), entry.getValue(), partial));
|
|
}
|
|
|
|
private static <T extends FieldDescriptorLite<T>> Object replaceBuilders(
|
|
- T descriptor, Object value) {
|
|
+ T descriptor, Object value, boolean partial) {
|
|
if (value == null) {
|
|
return value;
|
|
}
|
|
@@ -981,7 +1007,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
List<Object> list = (List<Object>) value;
|
|
for (int i = 0; i < list.size(); i++) {
|
|
Object oldElement = list.get(i);
|
|
- Object newElement = replaceBuilder(oldElement);
|
|
+ Object newElement = replaceBuilder(oldElement, partial);
|
|
if (newElement != oldElement) {
|
|
// If the list contains a Message.Builder, then make a copy of that list and then
|
|
// modify the Message.Builder into a Message and return the new list. This way, the
|
|
@@ -995,14 +1021,21 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
}
|
|
return list;
|
|
} else {
|
|
- return replaceBuilder(value);
|
|
+ return replaceBuilder(value, partial);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
- private static Object replaceBuilder(Object value) {
|
|
- return (value instanceof MessageLite.Builder) ? ((MessageLite.Builder) value).build() : value;
|
|
+ private static Object replaceBuilder(Object value, boolean partial) {
|
|
+ if (!(value instanceof MessageLite.Builder)) {
|
|
+ return value;
|
|
+ }
|
|
+ MessageLite.Builder builder = (MessageLite.Builder) value;
|
|
+ if (partial) {
|
|
+ return builder.buildPartial();
|
|
+ }
|
|
+ return builder.build();
|
|
}
|
|
|
|
/** Returns a new Builder using the fields from {@code fieldSet}. */
|
|
@@ -1021,7 +1054,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
if (fields.isImmutable()) {
|
|
result.makeImmutable();
|
|
} else {
|
|
- replaceBuilders(result);
|
|
+ replaceBuilders(result, true);
|
|
}
|
|
return result;
|
|
}
|
|
@@ -1044,7 +1077,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
*/
|
|
public Object getField(final T descriptor) {
|
|
Object value = getFieldAllowBuilders(descriptor);
|
|
- return replaceBuilders(descriptor, value);
|
|
+ return replaceBuilders(descriptor, value, true);
|
|
}
|
|
|
|
/** Same as {@link #getField(F)}, but allow a {@link MessageLite.Builder} to be returned. */
|
|
@@ -1131,7 +1164,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
|
|
ensureIsMutable();
|
|
}
|
|
Object value = getRepeatedFieldAllowBuilders(descriptor, index);
|
|
- return replaceBuilder(value);
|
|
+ return replaceBuilder(value, true);
|
|
}
|
|
|
|
/**
|
|
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 27f5210..943f6ee 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
|
|
@@ -62,11 +62,50 @@ public abstract class GeneratedMessageLite<
|
|
BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
|
|
extends AbstractMessageLite<MessageType, BuilderType> {
|
|
|
|
+ /* For use by lite runtime only */
|
|
+ static final int UNINITIALIZED_SERIALIZED_SIZE = 0x7FFFFFFF;
|
|
+ private static final int MUTABLE_FLAG_MASK = 0x80000000;
|
|
+ private static final int MEMOIZED_SERIALIZED_SIZE_MASK = 0x7FFFFFFF;
|
|
+
|
|
+ /**
|
|
+ * We use the high bit of memoizedSerializedSize as the explicit mutability flag. It didn't make
|
|
+ * sense to have negative sizes anyway. Messages start as mutable.
|
|
+ *
|
|
+ * <p>Adding a standalone boolean would have added 8 bytes to every message instance.
|
|
+ *
|
|
+ * <p>We also reserve 0x7FFFFFFF as the "uninitialized" value.
|
|
+ */
|
|
+ private int memoizedSerializedSize = MUTABLE_FLAG_MASK | UNINITIALIZED_SERIALIZED_SIZE;
|
|
+
|
|
+ /* For use by the runtime only */
|
|
+ static final int UNINITIALIZED_HASH_CODE = 0;
|
|
+
|
|
/** 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;
|
|
+ boolean isMutable() {
|
|
+ return (memoizedSerializedSize & MUTABLE_FLAG_MASK) != 0;
|
|
+ }
|
|
+
|
|
+ void markImmutable() {
|
|
+ memoizedSerializedSize &= ~MUTABLE_FLAG_MASK;
|
|
+ }
|
|
+
|
|
+ int getMemoizedHashCode() {
|
|
+ return memoizedHashCode;
|
|
+ }
|
|
+
|
|
+ void setMemoizedHashCode(int value) {
|
|
+ memoizedHashCode = value;
|
|
+ }
|
|
+
|
|
+ void clearMemoizedHashCode() {
|
|
+ memoizedHashCode = UNINITIALIZED_HASH_CODE;
|
|
+ }
|
|
+
|
|
+ boolean hashCodeIsNotMemoized() {
|
|
+ return UNINITIALIZED_HASH_CODE == getMemoizedHashCode();
|
|
+ }
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked") // Guaranteed by runtime.
|
|
@@ -86,6 +125,10 @@ public abstract class GeneratedMessageLite<
|
|
return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
|
|
}
|
|
|
|
+ MessageType newMutableInstance() {
|
|
+ return (MessageType) dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ }
|
|
+
|
|
/**
|
|
* A reflective toString function. This is primarily intended as a developer aid, while keeping
|
|
* binary size down. The first line of the {@code toString()} representation includes a commented
|
|
@@ -106,11 +149,19 @@ public abstract class GeneratedMessageLite<
|
|
@SuppressWarnings("unchecked") // Guaranteed by runtime
|
|
@Override
|
|
public int hashCode() {
|
|
- if (memoizedHashCode != 0) {
|
|
- return memoizedHashCode;
|
|
+ if (isMutable()) {
|
|
+ return computeHashCode();
|
|
}
|
|
- memoizedHashCode = Protobuf.getInstance().schemaFor(this).hashCode(this);
|
|
- return memoizedHashCode;
|
|
+
|
|
+ if (hashCodeIsNotMemoized()) {
|
|
+ setMemoizedHashCode(computeHashCode());
|
|
+ }
|
|
+
|
|
+ return getMemoizedHashCode();
|
|
+ }
|
|
+
|
|
+ int computeHashCode() {
|
|
+ return Protobuf.getInstance().schemaFor(this).hashCode(this);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
|
|
@@ -173,6 +224,7 @@ public abstract class GeneratedMessageLite<
|
|
/** Called by subclasses to complete parsing. For use by generated code only. */
|
|
protected void makeImmutable() {
|
|
Protobuf.getInstance().schemaFor(this).makeImmutable(this);
|
|
+ markImmutable();
|
|
}
|
|
|
|
protected final <
|
|
@@ -198,8 +250,7 @@ public abstract class GeneratedMessageLite<
|
|
@SuppressWarnings("unchecked")
|
|
public final BuilderType toBuilder() {
|
|
BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
|
|
- builder.mergeFrom((MessageType) this);
|
|
- return builder;
|
|
+ return builder.mergeFrom((MessageType) this);
|
|
}
|
|
|
|
/**
|
|
@@ -256,27 +307,67 @@ public abstract class GeneratedMessageLite<
|
|
return dynamicMethod(method, null, null);
|
|
}
|
|
|
|
+ void clearMemoizedSerializedSize() {
|
|
+ setMemoizedSerializedSize(UNINITIALIZED_SERIALIZED_SIZE);
|
|
+ }
|
|
+
|
|
@Override
|
|
int getMemoizedSerializedSize() {
|
|
- return memoizedSerializedSize;
|
|
+ return memoizedSerializedSize & MEMOIZED_SERIALIZED_SIZE_MASK;
|
|
}
|
|
|
|
@Override
|
|
void setMemoizedSerializedSize(int size) {
|
|
- memoizedSerializedSize = size;
|
|
+ if (size < 0) {
|
|
+ throw new IllegalStateException("serialized size must be non-negative, was " + size);
|
|
+ }
|
|
+ memoizedSerializedSize =
|
|
+ (memoizedSerializedSize & MUTABLE_FLAG_MASK) | (size & MEMOIZED_SERIALIZED_SIZE_MASK);
|
|
}
|
|
|
|
+ @Override
|
|
public void writeTo(CodedOutputStream output) throws IOException {
|
|
Protobuf.getInstance()
|
|
.schemaFor(this)
|
|
.writeTo(this, CodedOutputStreamWriter.forCodedOutput(output));
|
|
}
|
|
|
|
+ @Override
|
|
+ int getSerializedSize(Schema schema) {
|
|
+ if (isMutable()) {
|
|
+ // The serialized size should never be memoized for mutable instances.
|
|
+ int size = computeSerializedSize(schema);
|
|
+ if (size < 0) {
|
|
+ throw new IllegalStateException("serialized size must be non-negative, was " + size);
|
|
+ }
|
|
+ return size;
|
|
+ }
|
|
+
|
|
+ // If memoizedSerializedSize has already been set, return it.
|
|
+ if (getMemoizedSerializedSize() != UNINITIALIZED_SERIALIZED_SIZE) {
|
|
+ return getMemoizedSerializedSize();
|
|
+ }
|
|
+
|
|
+ // Need to compute and memoize the serialized size.
|
|
+ int size = computeSerializedSize(schema);
|
|
+ setMemoizedSerializedSize(size);
|
|
+ return size;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
public int getSerializedSize() {
|
|
- if (memoizedSerializedSize == -1) {
|
|
- memoizedSerializedSize = Protobuf.getInstance().schemaFor(this).getSerializedSize(this);
|
|
+ // Calling this with 'null' to delay schema lookup in case the serializedSize is already
|
|
+ // memoized.
|
|
+ return getSerializedSize(null);
|
|
}
|
|
- return memoizedSerializedSize;
|
|
+
|
|
+ private int computeSerializedSize(Schema<?> nullableSchema) {
|
|
+ if (nullableSchema == null) {
|
|
+ return Protobuf.getInstance().schemaFor(this).getSerializedSize(this);
|
|
+ } else {
|
|
+ return ((Schema<GeneratedMessageLite<MessageType, BuilderType>>) nullableSchema)
|
|
+ .getSerializedSize(this);
|
|
+ }
|
|
}
|
|
|
|
/** Constructs a {@link MessageInfo} for this message type. */
|
|
@@ -316,6 +407,7 @@ public abstract class GeneratedMessageLite<
|
|
protected static <T extends GeneratedMessageLite<?, ?>> void registerDefaultInstance(
|
|
Class<T> clazz, T defaultInstance) {
|
|
defaultInstanceMap.put(clazz, defaultInstance);
|
|
+ defaultInstance.makeImmutable();
|
|
}
|
|
|
|
protected static Object newMessageInfo(
|
|
@@ -340,13 +432,19 @@ public abstract class GeneratedMessageLite<
|
|
|
|
private final MessageType defaultInstance;
|
|
protected MessageType instance;
|
|
- protected boolean isBuilt;
|
|
|
|
protected Builder(MessageType defaultInstance) {
|
|
this.defaultInstance = defaultInstance;
|
|
- this.instance =
|
|
- (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
- isBuilt = false;
|
|
+ if (defaultInstance.isMutable()) {
|
|
+ throw new IllegalArgumentException("Default instance must be immutable.");
|
|
+ }
|
|
+ // this.instance should be set to defaultInstance but some tests rely on newBuilder().build()
|
|
+ // creating unique instances.
|
|
+ this.instance = newMutableInstance();
|
|
+ }
|
|
+
|
|
+ private MessageType newMutableInstance() {
|
|
+ return defaultInstance.newMutableInstance();
|
|
}
|
|
|
|
/**
|
|
@@ -354,15 +452,13 @@ public abstract class GeneratedMessageLite<
|
|
* state before the write happens to preserve immutability guarantees.
|
|
*/
|
|
protected final void copyOnWrite() {
|
|
- if (isBuilt) {
|
|
+ if (!instance.isMutable()) {
|
|
copyOnWriteInternal();
|
|
- isBuilt = false;
|
|
}
|
|
}
|
|
|
|
protected void copyOnWriteInternal() {
|
|
- MessageType newInstance =
|
|
- (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ MessageType newInstance = newMutableInstance();
|
|
mergeFromInstance(newInstance, instance);
|
|
instance = newInstance;
|
|
}
|
|
@@ -374,27 +470,28 @@ public abstract class GeneratedMessageLite<
|
|
|
|
@Override
|
|
public final BuilderType clear() {
|
|
- // No need to copy on write since we're dropping the instance anyways.
|
|
- instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ // No need to copy on write since we're dropping the instance anyway.
|
|
+ if (defaultInstance.isMutable()) {
|
|
+ throw new IllegalArgumentException("Default instance must be immutable.");
|
|
+ }
|
|
+ instance = newMutableInstance(); // should be defaultInstance;
|
|
return (BuilderType) this;
|
|
}
|
|
|
|
@Override
|
|
public BuilderType clone() {
|
|
BuilderType builder = (BuilderType) getDefaultInstanceForType().newBuilderForType();
|
|
- builder.mergeFrom(buildPartial());
|
|
+ builder.instance = buildPartial();
|
|
return builder;
|
|
}
|
|
|
|
@Override
|
|
public MessageType buildPartial() {
|
|
- if (isBuilt) {
|
|
+ if (!instance.isMutable()) {
|
|
return instance;
|
|
}
|
|
|
|
instance.makeImmutable();
|
|
-
|
|
- isBuilt = true;
|
|
return instance;
|
|
}
|
|
|
|
@@ -414,12 +511,15 @@ public abstract class GeneratedMessageLite<
|
|
|
|
/** All subclasses implement this. */
|
|
public BuilderType mergeFrom(MessageType message) {
|
|
+ if (getDefaultInstanceForType().equals(message)) {
|
|
+ return (BuilderType) this;
|
|
+ }
|
|
copyOnWrite();
|
|
mergeFromInstance(instance, message);
|
|
return (BuilderType) this;
|
|
}
|
|
|
|
- private void mergeFromInstance(MessageType dest, MessageType src) {
|
|
+ private static <MessageType> void mergeFromInstance(MessageType dest, MessageType src) {
|
|
Protobuf.getInstance().schemaFor(dest).mergeFrom(dest, src);
|
|
}
|
|
|
|
@@ -930,7 +1030,9 @@ public abstract class GeneratedMessageLite<
|
|
@Override
|
|
protected void copyOnWriteInternal() {
|
|
super.copyOnWriteInternal();
|
|
- instance.extensions = instance.extensions.clone();
|
|
+ if (instance.extensions != FieldSet.emptySet()) {
|
|
+ instance.extensions = instance.extensions.clone();
|
|
+ }
|
|
}
|
|
|
|
private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
|
|
@@ -944,7 +1046,7 @@ public abstract class GeneratedMessageLite<
|
|
|
|
@Override
|
|
public final MessageType buildPartial() {
|
|
- if (isBuilt) {
|
|
+ if (!instance.isMutable()) {
|
|
return instance;
|
|
}
|
|
|
|
@@ -1528,7 +1630,7 @@ public abstract class GeneratedMessageLite<
|
|
T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
|
throws InvalidProtocolBufferException {
|
|
@SuppressWarnings("unchecked") // Guaranteed by protoc
|
|
- T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ T result = instance.newMutableInstance();
|
|
try {
|
|
// TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
|
|
// fast path.
|
|
@@ -1554,15 +1656,12 @@ public abstract class GeneratedMessageLite<
|
|
T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
|
|
throws InvalidProtocolBufferException {
|
|
@SuppressWarnings("unchecked") // Guaranteed by protoc
|
|
- T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ T result = instance.newMutableInstance();
|
|
try {
|
|
Schema<T> schema = Protobuf.getInstance().schemaFor(result);
|
|
schema.mergeFrom(
|
|
result, input, offset, offset + length, new ArrayDecoders.Registers(extensionRegistry));
|
|
schema.makeImmutable(result);
|
|
- if (result.memoizedHashCode != 0) {
|
|
- throw new RuntimeException();
|
|
- }
|
|
} catch (IOException e) {
|
|
if (e.getCause() instanceof InvalidProtocolBufferException) {
|
|
throw (InvalidProtocolBufferException) e.getCause();
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
|
|
index 86f88a0..e322604 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
|
|
@@ -133,6 +133,10 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
return internalGetFieldAccessorTable().descriptor;
|
|
}
|
|
|
|
+ // TODO(b/248143958): This method should be removed. It enables parsing directly into an
|
|
+ // "immutable" message. Have to leave it for now to support old gencode.
|
|
+ // @deprecated use newBuilder().mergeFrom() instead
|
|
+ @Deprecated
|
|
protected void mergeFromAndMakeImmutableInternal(
|
|
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
|
throws InvalidProtocolBufferException {
|
|
@@ -299,13 +303,14 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
|
|
@Override
|
|
public UnknownFieldSet getUnknownFields() {
|
|
- throw new UnsupportedOperationException(
|
|
- "This is supposed to be overridden by subclasses.");
|
|
+ return unknownFields;
|
|
}
|
|
|
|
/**
|
|
* Called by subclasses to parse an unknown field.
|
|
*
|
|
+ * <p>TODO(b/248153893) remove this method
|
|
+ *
|
|
* @return {@code true} unless the tag is an end-group tag.
|
|
*/
|
|
protected boolean parseUnknownField(
|
|
@@ -323,6 +328,8 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
/**
|
|
* Delegates to parseUnknownField. This method is obsolete, but we must retain it for
|
|
* compatibility with older generated code.
|
|
+ *
|
|
+ * <p>TODO(b/248153893) remove this method
|
|
*/
|
|
protected boolean parseUnknownFieldProto3(
|
|
CodedInputStream input,
|
|
@@ -547,8 +554,18 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
// to dispatch dirty invalidations. See GeneratedMessageV3.BuilderListener.
|
|
private boolean isClean;
|
|
|
|
- private UnknownFieldSet unknownFields =
|
|
- UnknownFieldSet.getDefaultInstance();
|
|
+ /**
|
|
+ * This field holds either an {@link UnknownFieldSet} or {@link UnknownFieldSet.Builder}.
|
|
+ *
|
|
+ * <p>We use an object because it should only be one or the other of those things at a time and
|
|
+ * Object is the only common base. This also saves space.
|
|
+ *
|
|
+ * <p>Conversions are lazy: if {@link #setUnknownFields} is called, this will contain {@link
|
|
+ * UnknownFieldSet}. If unknown fields are merged into this builder, the current {@link
|
|
+ * UnknownFieldSet} will be converted to a {@link UnknownFieldSet.Builder} and left that way
|
|
+ * until either {@link #setUnknownFields} or {@link #buildPartial} or {@link #build} is called.
|
|
+ */
|
|
+ private Object unknownFieldsOrBuilder = UnknownFieldSet.getDefaultInstance();
|
|
|
|
protected Builder() {
|
|
this(null);
|
|
@@ -604,7 +621,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
*/
|
|
@Override
|
|
public BuilderType clear() {
|
|
- unknownFields = UnknownFieldSet.getDefaultInstance();
|
|
+ unknownFieldsOrBuilder = UnknownFieldSet.getDefaultInstance();
|
|
onChanged();
|
|
return (BuilderType) this;
|
|
}
|
|
@@ -757,7 +774,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
}
|
|
|
|
private BuilderType setUnknownFieldsInternal(final UnknownFieldSet unknownFields) {
|
|
- this.unknownFields = unknownFields;
|
|
+ unknownFieldsOrBuilder = unknownFields;
|
|
onChanged();
|
|
return (BuilderType) this;
|
|
}
|
|
@@ -776,12 +793,20 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
}
|
|
|
|
@Override
|
|
- public BuilderType mergeUnknownFields(
|
|
- final UnknownFieldSet unknownFields) {
|
|
- return setUnknownFields(
|
|
- UnknownFieldSet.newBuilder(this.unknownFields)
|
|
- .mergeFrom(unknownFields)
|
|
- .build());
|
|
+ public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
|
|
+ if (UnknownFieldSet.getDefaultInstance().equals(unknownFields)) {
|
|
+ return (BuilderType) this;
|
|
+ }
|
|
+
|
|
+ if (UnknownFieldSet.getDefaultInstance().equals(unknownFieldsOrBuilder)) {
|
|
+ unknownFieldsOrBuilder = unknownFields;
|
|
+ onChanged();
|
|
+ return (BuilderType) this;
|
|
+ }
|
|
+
|
|
+ getUnknownFieldSetBuilder().mergeFrom(unknownFields);
|
|
+ onChanged();
|
|
+ return (BuilderType) this;
|
|
}
|
|
|
|
|
|
@@ -817,7 +842,50 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
|
|
@Override
|
|
public final UnknownFieldSet getUnknownFields() {
|
|
- return unknownFields;
|
|
+ if (unknownFieldsOrBuilder instanceof UnknownFieldSet) {
|
|
+ return (UnknownFieldSet) unknownFieldsOrBuilder;
|
|
+ } else {
|
|
+ return ((UnknownFieldSet.Builder) unknownFieldsOrBuilder).buildPartial();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Called by generated subclasses to parse an unknown field.
|
|
+ *
|
|
+ * @return {@code true} unless the tag is an end-group tag.
|
|
+ */
|
|
+ protected boolean parseUnknownField(
|
|
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry, int tag)
|
|
+ throws IOException {
|
|
+ if (input.shouldDiscardUnknownFields()) {
|
|
+ return input.skipField(tag);
|
|
+ }
|
|
+ return getUnknownFieldSetBuilder().mergeFieldFrom(tag, input);
|
|
+ }
|
|
+
|
|
+ /** Called by generated subclasses to add to the unknown field set. */
|
|
+ protected final void mergeUnknownLengthDelimitedField(int number, ByteString bytes) {
|
|
+ getUnknownFieldSetBuilder().mergeLengthDelimitedField(number, bytes);
|
|
+ }
|
|
+
|
|
+ /** Called by generated subclasses to add to the unknown field set. */
|
|
+ protected final void mergeUnknownVarintField(int number, int value) {
|
|
+ getUnknownFieldSetBuilder().mergeVarintField(number, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected UnknownFieldSet.Builder getUnknownFieldSetBuilder() {
|
|
+ if (unknownFieldsOrBuilder instanceof UnknownFieldSet) {
|
|
+ unknownFieldsOrBuilder = ((UnknownFieldSet) unknownFieldsOrBuilder).toBuilder();
|
|
+ }
|
|
+ onChanged();
|
|
+ return (UnknownFieldSet.Builder) unknownFieldsOrBuilder;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void setUnknownFieldSetBuilder(UnknownFieldSet.Builder builder) {
|
|
+ unknownFieldsOrBuilder = builder;
|
|
+ onChanged();
|
|
}
|
|
|
|
/**
|
|
@@ -1609,7 +1677,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
private FieldSet<FieldDescriptor> buildExtensions() {
|
|
return extensions == null
|
|
? (FieldSet<FieldDescriptor>) FieldSet.emptySet()
|
|
- : extensions.build();
|
|
+ : extensions.buildPartial();
|
|
}
|
|
|
|
@Override
|
|
@@ -1815,6 +1883,20 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
}
|
|
}
|
|
|
|
+ @Override
|
|
+ protected boolean parseUnknownField(
|
|
+ CodedInputStream input, ExtensionRegistryLite extensionRegistry, int tag)
|
|
+ throws IOException {
|
|
+ ensureExtensionsIsMutable();
|
|
+ return MessageReflection.mergeFieldFrom(
|
|
+ input,
|
|
+ input.shouldDiscardUnknownFields() ? null : getUnknownFieldSetBuilder(),
|
|
+ extensionRegistry,
|
|
+ getDescriptorForType(),
|
|
+ new MessageReflection.ExtensionBuilderAdapter(extensions),
|
|
+ tag);
|
|
+ }
|
|
+
|
|
private void verifyContainingType(final FieldDescriptor field) {
|
|
if (field.getContainingType() != getDescriptorForType()) {
|
|
throw new IllegalArgumentException(
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
|
|
index 4aea952..3a3a70f 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
|
|
@@ -32,12 +32,15 @@ package com.google.protobuf;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Modifier;
|
|
+import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
+import java.util.Map.Entry;
|
|
import java.util.Set;
|
|
-import java.util.TreeSet;
|
|
+import java.util.TreeMap;
|
|
|
|
/** Helps generate {@link String} representations of {@link MessageLite} protos. */
|
|
final class MessageLiteToString {
|
|
@@ -46,6 +49,11 @@ final class MessageLiteToString {
|
|
private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
|
|
private static final String MAP_SUFFIX = "Map";
|
|
private static final String BYTES_SUFFIX = "Bytes";
|
|
+ private static final char[] INDENT_BUFFER = new char[80];
|
|
+
|
|
+ static {
|
|
+ Arrays.fill(INDENT_BUFFER, ' ');
|
|
+ }
|
|
|
|
/**
|
|
* Returns a {@link String} representation of the {@link MessageLite} object. The first line of
|
|
@@ -73,37 +81,51 @@ final class MessageLiteToString {
|
|
// Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
|
|
// getFooList() and getFooMap() which might be useful for building an object's string
|
|
// representation.
|
|
- Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
|
|
- Map<String, Method> nameToMethod = new HashMap<String, Method>();
|
|
- Set<String> getters = new TreeSet<String>();
|
|
+ Set<String> setters = new HashSet<>();
|
|
+ Map<String, Method> hazzers = new HashMap<>();
|
|
+ Map<String, Method> getters = new TreeMap<>();
|
|
for (Method method : messageLite.getClass().getDeclaredMethods()) {
|
|
- nameToMethod.put(method.getName(), method);
|
|
- if (method.getParameterTypes().length == 0) {
|
|
- nameToNoArgMethod.put(method.getName(), method);
|
|
+ if (Modifier.isStatic(method.getModifiers())) {
|
|
+ continue;
|
|
+ }
|
|
+ if (method.getName().length() < 3) {
|
|
+ continue;
|
|
+ }
|
|
|
|
- if (method.getName().startsWith("get")) {
|
|
- getters.add(method.getName());
|
|
- }
|
|
+ if (method.getName().startsWith("set")) {
|
|
+ setters.add(method.getName());
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (!Modifier.isPublic(method.getModifiers())) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (method.getParameterTypes().length != 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (method.getName().startsWith("has")) {
|
|
+ hazzers.put(method.getName(), method);
|
|
+ } else if (method.getName().startsWith("get")) {
|
|
+ getters.put(method.getName(), method);
|
|
}
|
|
}
|
|
|
|
- for (String getter : getters) {
|
|
- String suffix = getter.startsWith("get") ? getter.substring(3) : getter;
|
|
+ for (Entry<String, Method> getter : getters.entrySet()) {
|
|
+ String suffix = getter.getKey().substring(3);
|
|
if (suffix.endsWith(LIST_SUFFIX)
|
|
&& !suffix.endsWith(BUILDER_LIST_SUFFIX)
|
|
// Sometimes people have fields named 'list' that aren't repeated.
|
|
&& !suffix.equals(LIST_SUFFIX)) {
|
|
- String camelCase =
|
|
- suffix.substring(0, 1).toLowerCase()
|
|
- + suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
|
|
// Try to reflectively get the value and toString() the field as if it were repeated. This
|
|
// only works if the method names have not been proguarded out or renamed.
|
|
- Method listMethod = nameToNoArgMethod.get(getter);
|
|
+ Method listMethod = getter.getValue();
|
|
if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
|
|
printField(
|
|
buffer,
|
|
indent,
|
|
- camelCaseToSnakeCase(camelCase),
|
|
+ suffix.substring(0, suffix.length() - LIST_SUFFIX.length()),
|
|
GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
|
|
continue;
|
|
}
|
|
@@ -111,12 +133,9 @@ final class MessageLiteToString {
|
|
if (suffix.endsWith(MAP_SUFFIX)
|
|
// Sometimes people have fields named 'map' that aren't maps.
|
|
&& !suffix.equals(MAP_SUFFIX)) {
|
|
- String camelCase =
|
|
- suffix.substring(0, 1).toLowerCase()
|
|
- + suffix.substring(1, suffix.length() - MAP_SUFFIX.length());
|
|
// Try to reflectively get the value and toString() the field as if it were a map. This only
|
|
// works if the method names have not been proguarded out or renamed.
|
|
- Method mapMethod = nameToNoArgMethod.get(getter);
|
|
+ Method mapMethod = getter.getValue();
|
|
if (mapMethod != null
|
|
&& mapMethod.getReturnType().equals(Map.class)
|
|
// Skip the deprecated getter method with no prefix "Map" when the field name ends with
|
|
@@ -127,29 +146,25 @@ final class MessageLiteToString {
|
|
printField(
|
|
buffer,
|
|
indent,
|
|
- camelCaseToSnakeCase(camelCase),
|
|
+ suffix.substring(0, suffix.length() - MAP_SUFFIX.length()),
|
|
GeneratedMessageLite.invokeOrDie(mapMethod, messageLite));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
- Method setter = nameToMethod.get("set" + suffix);
|
|
- if (setter == null) {
|
|
+ if (!setters.contains("set" + suffix)) {
|
|
continue;
|
|
}
|
|
if (suffix.endsWith(BYTES_SUFFIX)
|
|
- && nameToNoArgMethod.containsKey(
|
|
- "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
|
|
+ && getters.containsKey("get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
|
|
// Heuristic to skip bytes based accessors for string fields.
|
|
continue;
|
|
}
|
|
|
|
- String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
|
|
-
|
|
// Try to reflectively get the value and toString() the field as if it were optional. This
|
|
// only works if the method names have not been proguarded out or renamed.
|
|
- Method getMethod = nameToNoArgMethod.get("get" + suffix);
|
|
- Method hasMethod = nameToNoArgMethod.get("has" + suffix);
|
|
+ Method getMethod = getter.getValue();
|
|
+ Method hasMethod = hazzers.get("has" + suffix);
|
|
// TODO(dweis): Fix proto3 semantics.
|
|
if (getMethod != null) {
|
|
Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
|
|
@@ -159,7 +174,7 @@ final class MessageLiteToString {
|
|
: (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
|
|
// TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
|
|
if (hasValue) {
|
|
- printField(buffer, indent, camelCaseToSnakeCase(camelCase), value);
|
|
+ printField(buffer, indent, suffix, value);
|
|
}
|
|
continue;
|
|
}
|
|
@@ -215,10 +230,10 @@ final class MessageLiteToString {
|
|
*
|
|
* @param buffer the buffer to write to
|
|
* @param indent the number of spaces the proto should be indented by
|
|
- * @param name the field name (in lower underscore case)
|
|
+ * @param name the field name (in PascalCase)
|
|
* @param object the object value of the field
|
|
*/
|
|
- static final void printField(StringBuilder buffer, int indent, String name, Object object) {
|
|
+ static void printField(StringBuilder buffer, int indent, String name, Object object) {
|
|
if (object instanceof List<?>) {
|
|
List<?> list = (List<?>) object;
|
|
for (Object entry : list) {
|
|
@@ -235,10 +250,8 @@ final class MessageLiteToString {
|
|
}
|
|
|
|
buffer.append('\n');
|
|
- for (int i = 0; i < indent; i++) {
|
|
- buffer.append(' ');
|
|
- }
|
|
- buffer.append(name);
|
|
+ indent(indent, buffer);
|
|
+ buffer.append(pascalCaseToSnakeCase(name));
|
|
|
|
if (object instanceof String) {
|
|
buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
|
|
@@ -248,9 +261,7 @@ final class MessageLiteToString {
|
|
buffer.append(" {");
|
|
reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
|
|
buffer.append("\n");
|
|
- for (int i = 0; i < indent; i++) {
|
|
- buffer.append(' ');
|
|
- }
|
|
+ indent(indent, buffer);
|
|
buffer.append("}");
|
|
} else if (object instanceof Map.Entry<?, ?>) {
|
|
buffer.append(" {");
|
|
@@ -258,19 +269,33 @@ final class MessageLiteToString {
|
|
printField(buffer, indent + 2, "key", entry.getKey());
|
|
printField(buffer, indent + 2, "value", entry.getValue());
|
|
buffer.append("\n");
|
|
- for (int i = 0; i < indent; i++) {
|
|
- buffer.append(' ');
|
|
- }
|
|
+ indent(indent, buffer);
|
|
buffer.append("}");
|
|
} else {
|
|
buffer.append(": ").append(object.toString());
|
|
}
|
|
}
|
|
|
|
- private static final String camelCaseToSnakeCase(String camelCase) {
|
|
+ private static void indent(int indent, StringBuilder buffer) {
|
|
+ while (indent > 0) {
|
|
+ int partialIndent = indent;
|
|
+ if (partialIndent > INDENT_BUFFER.length) {
|
|
+ partialIndent = INDENT_BUFFER.length;
|
|
+ }
|
|
+ buffer.append(INDENT_BUFFER, 0, partialIndent);
|
|
+ indent -= partialIndent;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static String pascalCaseToSnakeCase(String pascalCase) {
|
|
+ if (pascalCase.isEmpty()) {
|
|
+ return pascalCase;
|
|
+ }
|
|
+
|
|
StringBuilder builder = new StringBuilder();
|
|
- for (int i = 0; i < camelCase.length(); i++) {
|
|
- char ch = camelCase.charAt(i);
|
|
+ builder.append(Character.toLowerCase(pascalCase.charAt(0)));
|
|
+ for (int i = 1; i < pascalCase.length(); i++) {
|
|
+ char ch = pascalCase.charAt(i);
|
|
if (Character.isUpperCase(ch)) {
|
|
builder.append("_");
|
|
}
|
|
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 6741e1c..13a6b8d 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
|
|
@@ -30,6 +30,7 @@
|
|
|
|
package com.google.protobuf;
|
|
|
|
+import com.google.protobuf.Descriptors.Descriptor;
|
|
import com.google.protobuf.Descriptors.FieldDescriptor;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
@@ -323,6 +324,34 @@ class MessageReflection {
|
|
Message defaultInstance)
|
|
throws IOException;
|
|
|
|
+ /**
|
|
+ * Read the given group field from the wire, merging with the existing field if it is already
|
|
+ * present.
|
|
+ *
|
|
+ * <p>For extensions, defaultInstance must be specified. For regular fields, defaultInstance can
|
|
+ * be null.
|
|
+ */
|
|
+ void mergeGroup(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException;
|
|
+
|
|
+ /**
|
|
+ * Read the given message field from the wire, merging with the existing field if it is already
|
|
+ * present.
|
|
+ *
|
|
+ * <p>For extensions, defaultInstance must be specified. For regular fields, defaultInstance can
|
|
+ * be null.
|
|
+ */
|
|
+ void mergeMessage(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException;
|
|
+
|
|
/** Returns the UTF8 validation level for the field. */
|
|
WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor);
|
|
|
|
@@ -349,6 +378,7 @@ class MessageReflection {
|
|
static class BuilderAdapter implements MergeTarget {
|
|
|
|
private final Message.Builder builder;
|
|
+ private boolean hasNestedBuilders = true;
|
|
|
|
@Override
|
|
public Descriptors.Descriptor getDescriptorForType() {
|
|
@@ -364,6 +394,17 @@ class MessageReflection {
|
|
return builder.getField(field);
|
|
}
|
|
|
|
+ private Message.Builder getFieldBuilder(Descriptors.FieldDescriptor field) {
|
|
+ if (hasNestedBuilders) {
|
|
+ try {
|
|
+ return builder.getFieldBuilder(field);
|
|
+ } catch (UnsupportedOperationException e) {
|
|
+ hasNestedBuilders = false;
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
@Override
|
|
public boolean hasField(Descriptors.FieldDescriptor field) {
|
|
return builder.hasField(field);
|
|
@@ -371,6 +412,12 @@ class MessageReflection {
|
|
|
|
@Override
|
|
public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
|
|
+ if (!field.isRepeated() && value instanceof MessageLite.Builder) {
|
|
+ if (value != getFieldBuilder(field)) {
|
|
+ builder.setField(field, ((MessageLite.Builder) value).buildPartial());
|
|
+ }
|
|
+ return this;
|
|
+ }
|
|
builder.setField(field, value);
|
|
return this;
|
|
}
|
|
@@ -384,12 +431,18 @@ class MessageReflection {
|
|
@Override
|
|
public MergeTarget setRepeatedField(
|
|
Descriptors.FieldDescriptor field, int index, Object value) {
|
|
+ if (value instanceof MessageLite.Builder) {
|
|
+ value = ((MessageLite.Builder) value).buildPartial();
|
|
+ }
|
|
builder.setRepeatedField(field, index, value);
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
|
|
+ if (value instanceof MessageLite.Builder) {
|
|
+ value = ((MessageLite.Builder) value).buildPartial();
|
|
+ }
|
|
builder.addRepeatedField(field, value);
|
|
return this;
|
|
}
|
|
@@ -499,15 +552,88 @@ class MessageReflection {
|
|
return subBuilder.buildPartial();
|
|
}
|
|
|
|
+ @Override
|
|
+ public void mergeGroup(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ Message.Builder subBuilder;
|
|
+ if (hasField(field)) {
|
|
+ subBuilder = getFieldBuilder(field);
|
|
+ if (subBuilder != null) {
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ return;
|
|
+ } else {
|
|
+ subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ subBuilder.mergeFrom((Message) getField(field));
|
|
+ }
|
|
+ } else {
|
|
+ subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ }
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder.buildPartial());
|
|
+ } else {
|
|
+ Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void mergeMessage(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ Descriptors.FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ Message.Builder subBuilder;
|
|
+ if (hasField(field)) {
|
|
+ subBuilder = getFieldBuilder(field);
|
|
+ if (subBuilder != null) {
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ return;
|
|
+ } else {
|
|
+ subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ subBuilder.mergeFrom((Message) getField(field));
|
|
+ }
|
|
+ } else {
|
|
+ subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ }
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder.buildPartial());
|
|
+ } else {
|
|
+ Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Message.Builder newMessageFieldInstance(
|
|
+ FieldDescriptor field, Message defaultInstance) {
|
|
+ // When default instance is not null. The field is an extension field.
|
|
+ if (defaultInstance != null) {
|
|
+ return defaultInstance.newBuilderForType();
|
|
+ } else {
|
|
+ return builder.newBuilderForField(field);
|
|
+ }
|
|
+ }
|
|
+
|
|
@Override
|
|
public MergeTarget newMergeTargetForField(
|
|
Descriptors.FieldDescriptor field, Message defaultInstance) {
|
|
Message.Builder subBuilder;
|
|
- if (defaultInstance != null) {
|
|
- subBuilder = defaultInstance.newBuilderForType();
|
|
- } else {
|
|
- subBuilder = builder.newBuilderForField(field);
|
|
+ if (!field.isRepeated() && hasField(field)) {
|
|
+ subBuilder = getFieldBuilder(field);
|
|
+ if (subBuilder != null) {
|
|
+ return new BuilderAdapter(subBuilder);
|
|
+ }
|
|
}
|
|
+
|
|
+ subBuilder = newMessageFieldInstance(field, defaultInstance);
|
|
if (!field.isRepeated()) {
|
|
Message originalMessage = (Message) getField(field);
|
|
if (originalMessage != null) {
|
|
@@ -543,7 +669,7 @@ class MessageReflection {
|
|
|
|
@Override
|
|
public Object finish() {
|
|
- return builder.buildPartial();
|
|
+ return builder;
|
|
}
|
|
}
|
|
|
|
@@ -665,6 +791,276 @@ class MessageReflection {
|
|
return subBuilder.buildPartial();
|
|
}
|
|
|
|
+ @Override
|
|
+ public void mergeGroup(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ if (hasField(field)) {
|
|
+ MessageLite.Builder current = ((MessageLite) getField(field)).toBuilder();
|
|
+ input.readGroup(field.getNumber(), current, extensionRegistry);
|
|
+ Object unused = setField(field, current.buildPartial());
|
|
+ return;
|
|
+ }
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder.buildPartial());
|
|
+ } else {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void mergeMessage(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ if (hasField(field)) {
|
|
+ MessageLite.Builder current = ((MessageLite) getField(field)).toBuilder();
|
|
+ input.readMessage(current, extensionRegistry);
|
|
+ Object unused = setField(field, current.buildPartial());
|
|
+ return;
|
|
+ }
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder.buildPartial());
|
|
+ } else {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object parseMessageFromBytes(
|
|
+ ByteString bytes,
|
|
+ ExtensionRegistryLite registry,
|
|
+ Descriptors.FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ if (!field.isRepeated()) {
|
|
+ Message originalMessage = (Message) getField(field);
|
|
+ if (originalMessage != null) {
|
|
+ subBuilder.mergeFrom(originalMessage);
|
|
+ }
|
|
+ }
|
|
+ subBuilder.mergeFrom(bytes, registry);
|
|
+ return subBuilder.buildPartial();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget newMergeTargetForField(
|
|
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
|
|
+ throw new UnsupportedOperationException("newMergeTargetForField() called on FieldSet object");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget newEmptyTargetForField(
|
|
+ Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
|
|
+ throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
|
|
+ if (descriptor.needsUtf8Check()) {
|
|
+ return WireFormat.Utf8Validation.STRICT;
|
|
+ }
|
|
+ // TODO(b/248145492): support lazy strings for ExtesnsionSet.
|
|
+ return WireFormat.Utf8Validation.LOOSE;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object finish() {
|
|
+ throw new UnsupportedOperationException("finish() called on FieldSet object");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static class ExtensionBuilderAdapter implements MergeTarget {
|
|
+
|
|
+ private final FieldSet.Builder<Descriptors.FieldDescriptor> extensions;
|
|
+
|
|
+ ExtensionBuilderAdapter(FieldSet.Builder<Descriptors.FieldDescriptor> extensions) {
|
|
+ this.extensions = extensions;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Descriptors.Descriptor getDescriptorForType() {
|
|
+ throw new UnsupportedOperationException("getDescriptorForType() called on FieldSet object");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object getField(Descriptors.FieldDescriptor field) {
|
|
+ return extensions.getField(field);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasField(Descriptors.FieldDescriptor field) {
|
|
+ return extensions.hasField(field);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
|
|
+ extensions.setField(field, value);
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget clearField(Descriptors.FieldDescriptor field) {
|
|
+ extensions.clearField(field);
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget setRepeatedField(
|
|
+ Descriptors.FieldDescriptor field, int index, Object value) {
|
|
+ extensions.setRepeatedField(field, index, value);
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
|
|
+ extensions.addRepeatedField(field, value);
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
|
|
+ // Nothing to clear.
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ContainerType getContainerType() {
|
|
+ return ContainerType.EXTENSION_SET;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ExtensionRegistry.ExtensionInfo findExtensionByName(
|
|
+ ExtensionRegistry registry, String name) {
|
|
+ return registry.findImmutableExtensionByName(name);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
|
|
+ ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
|
|
+ return registry.findImmutableExtensionByNumber(containingType, fieldNumber);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object parseGroup(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite registry,
|
|
+ Descriptors.FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ if (!field.isRepeated()) {
|
|
+ Message originalMessage = (Message) getField(field);
|
|
+ if (originalMessage != null) {
|
|
+ subBuilder.mergeFrom(originalMessage);
|
|
+ }
|
|
+ }
|
|
+ input.readGroup(field.getNumber(), subBuilder, registry);
|
|
+ return subBuilder.buildPartial();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object parseMessage(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite registry,
|
|
+ Descriptors.FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ if (!field.isRepeated()) {
|
|
+ Message originalMessage = (Message) getField(field);
|
|
+ if (originalMessage != null) {
|
|
+ subBuilder.mergeFrom(originalMessage);
|
|
+ }
|
|
+ }
|
|
+ input.readMessage(subBuilder, registry);
|
|
+ return subBuilder.buildPartial();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void mergeGroup(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ if (hasField(field)) {
|
|
+ Object fieldOrBuilder = extensions.getFieldAllowBuilders(field);
|
|
+ MessageLite.Builder subBuilder;
|
|
+ if (fieldOrBuilder instanceof MessageLite.Builder) {
|
|
+ subBuilder = (MessageLite.Builder) fieldOrBuilder;
|
|
+ } else {
|
|
+ subBuilder = ((MessageLite) fieldOrBuilder).toBuilder();
|
|
+ extensions.setField(field, subBuilder);
|
|
+ }
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ return;
|
|
+ }
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder);
|
|
+ } else {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void mergeMessage(
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
+ FieldDescriptor field,
|
|
+ Message defaultInstance)
|
|
+ throws IOException {
|
|
+ if (!field.isRepeated()) {
|
|
+ if (hasField(field)) {
|
|
+ Object fieldOrBuilder = extensions.getFieldAllowBuilders(field);
|
|
+ MessageLite.Builder subBuilder;
|
|
+ if (fieldOrBuilder instanceof MessageLite.Builder) {
|
|
+ subBuilder = (MessageLite.Builder) fieldOrBuilder;
|
|
+ } else {
|
|
+ subBuilder = ((MessageLite) fieldOrBuilder).toBuilder();
|
|
+ extensions.setField(field, subBuilder);
|
|
+ }
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ return;
|
|
+ }
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = setField(field, subBuilder);
|
|
+ } else {
|
|
+ Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
|
+ input.readMessage(subBuilder, extensionRegistry);
|
|
+ Object unused = addRepeatedField(field, subBuilder.buildPartial());
|
|
+ }
|
|
+ }
|
|
+
|
|
@Override
|
|
public Object parseMessageFromBytes(
|
|
ByteString bytes,
|
|
@@ -700,7 +1096,7 @@ class MessageReflection {
|
|
if (descriptor.needsUtf8Check()) {
|
|
return WireFormat.Utf8Validation.STRICT;
|
|
}
|
|
- // TODO(liujisi): support lazy strings for ExtesnsionSet.
|
|
+ // TODO(b/248145492): support lazy strings for ExtesnsionSet.
|
|
return WireFormat.Utf8Validation.LOOSE;
|
|
}
|
|
|
|
@@ -829,13 +1225,13 @@ class MessageReflection {
|
|
switch (field.getType()) {
|
|
case GROUP:
|
|
{
|
|
- value = target.parseGroup(input, extensionRegistry, field, defaultInstance);
|
|
- break;
|
|
+ target.mergeGroup(input, extensionRegistry, field, defaultInstance);
|
|
+ return true;
|
|
}
|
|
case MESSAGE:
|
|
{
|
|
- value = target.parseMessage(input, extensionRegistry, field, defaultInstance);
|
|
- break;
|
|
+ target.mergeMessage(input, extensionRegistry, field, defaultInstance);
|
|
+ return true;
|
|
}
|
|
case ENUM:
|
|
final int rawValue = input.readEnum();
|
|
@@ -870,6 +1266,29 @@ class MessageReflection {
|
|
return true;
|
|
}
|
|
|
|
+ /** Read a message from the given input stream into the provided target and UnknownFieldSet. */
|
|
+ static void mergeMessageFrom(
|
|
+ Message.Builder target,
|
|
+ UnknownFieldSet.Builder unknownFields,
|
|
+ CodedInputStream input,
|
|
+ ExtensionRegistryLite extensionRegistry)
|
|
+ throws IOException {
|
|
+ BuilderAdapter builderAdapter = new BuilderAdapter(target);
|
|
+ Descriptor descriptorForType = target.getDescriptorForType();
|
|
+ while (true) {
|
|
+ final int tag = input.readTag();
|
|
+ if (tag == 0) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!mergeFieldFrom(
|
|
+ input, unknownFields, extensionRegistry, descriptorForType, builderAdapter, tag)) {
|
|
+ // end group tag
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into MergeTarget. */
|
|
private static void mergeMessageSetExtensionFromCodedStream(
|
|
CodedInputStream input,
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
|
|
index 33c8e91..8f873c1 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
|
|
@@ -42,7 +42,6 @@ import static com.google.protobuf.ArrayDecoders.decodeFixed64;
|
|
import static com.google.protobuf.ArrayDecoders.decodeFixed64List;
|
|
import static com.google.protobuf.ArrayDecoders.decodeFloat;
|
|
import static com.google.protobuf.ArrayDecoders.decodeFloatList;
|
|
-import static com.google.protobuf.ArrayDecoders.decodeGroupField;
|
|
import static com.google.protobuf.ArrayDecoders.decodeGroupList;
|
|
import static com.google.protobuf.ArrayDecoders.decodeMessageField;
|
|
import static com.google.protobuf.ArrayDecoders.decodeMessageList;
|
|
@@ -66,6 +65,8 @@ import static com.google.protobuf.ArrayDecoders.decodeVarint32;
|
|
import static com.google.protobuf.ArrayDecoders.decodeVarint32List;
|
|
import static com.google.protobuf.ArrayDecoders.decodeVarint64;
|
|
import static com.google.protobuf.ArrayDecoders.decodeVarint64List;
|
|
+import static com.google.protobuf.ArrayDecoders.mergeGroupField;
|
|
+import static com.google.protobuf.ArrayDecoders.mergeMessageField;
|
|
import static com.google.protobuf.ArrayDecoders.skipField;
|
|
|
|
import com.google.protobuf.ArrayDecoders.Registers;
|
|
@@ -1176,6 +1177,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
|
|
@Override
|
|
public void mergeFrom(T message, T other) {
|
|
+ checkMutable(message);
|
|
if (other == null) {
|
|
throw new NullPointerException();
|
|
}
|
|
@@ -1374,47 +1376,83 @@ final class MessageSchema<T> implements Schema<T> {
|
|
}
|
|
}
|
|
|
|
- private void mergeMessage(T message, T other, int pos) {
|
|
+ private void mergeMessage(T targetParent, T sourceParent, int pos) {
|
|
+ if (!isFieldPresent(sourceParent, pos)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
final int typeAndOffset = typeAndOffsetAt(pos);
|
|
final long offset = offset(typeAndOffset);
|
|
|
|
- if (!isFieldPresent(other, pos)) {
|
|
+ final Object source = UNSAFE.getObject(sourceParent, offset);
|
|
+ if (source == null) {
|
|
+ throw new IllegalStateException(
|
|
+ "Source subfield " + numberAt(pos) + " is present but null: " + sourceParent);
|
|
+ }
|
|
+
|
|
+ final Schema fieldSchema = getMessageFieldSchema(pos);
|
|
+ if (!isFieldPresent(targetParent, pos)) {
|
|
+ if (!isMutable(source)) {
|
|
+ // Can safely share source if it is immutable
|
|
+ UNSAFE.putObject(targetParent, offset, source);
|
|
+ } else {
|
|
+ // Make a safetey copy of source
|
|
+ final Object copyOfSource = fieldSchema.newInstance();
|
|
+ fieldSchema.mergeFrom(copyOfSource, source);
|
|
+ UNSAFE.putObject(targetParent, offset, copyOfSource);
|
|
+ }
|
|
+ setFieldPresent(targetParent, pos);
|
|
return;
|
|
}
|
|
|
|
- Object mine = UnsafeUtil.getObject(message, offset);
|
|
- Object theirs = UnsafeUtil.getObject(other, offset);
|
|
- if (mine != null && theirs != null) {
|
|
- Object merged = Internal.mergeMessage(mine, theirs);
|
|
- UnsafeUtil.putObject(message, offset, merged);
|
|
- setFieldPresent(message, pos);
|
|
- } else if (theirs != null) {
|
|
- UnsafeUtil.putObject(message, offset, theirs);
|
|
- setFieldPresent(message, pos);
|
|
+ // Sub-message is present, merge from source
|
|
+ Object target = UNSAFE.getObject(targetParent, offset);
|
|
+ if (!isMutable(target)) {
|
|
+ Object newInstance = fieldSchema.newInstance();
|
|
+ fieldSchema.mergeFrom(newInstance, target);
|
|
+ UNSAFE.putObject(targetParent, offset, newInstance);
|
|
+ target = newInstance;
|
|
}
|
|
+ fieldSchema.mergeFrom(target, source);
|
|
}
|
|
|
|
- private void mergeOneofMessage(T message, T other, int pos) {
|
|
- int typeAndOffset = typeAndOffsetAt(pos);
|
|
+ private void mergeOneofMessage(T targetParent, T sourceParent, int pos) {
|
|
int number = numberAt(pos);
|
|
- long offset = offset(typeAndOffset);
|
|
-
|
|
- if (!isOneofPresent(other, number, pos)) {
|
|
+ if (!isOneofPresent(sourceParent, number, pos)) {
|
|
return;
|
|
}
|
|
- Object mine = null;
|
|
- if (isOneofPresent(message, number, pos)) {
|
|
- mine = UnsafeUtil.getObject(message, offset);
|
|
+
|
|
+ long offset = offset(typeAndOffsetAt(pos));
|
|
+ final Object source = UNSAFE.getObject(sourceParent, offset);
|
|
+ if (source == null) {
|
|
+ throw new IllegalStateException(
|
|
+ "Source subfield " + numberAt(pos) + " is present but null: " + sourceParent);
|
|
}
|
|
- Object theirs = UnsafeUtil.getObject(other, offset);
|
|
- if (mine != null && theirs != null) {
|
|
- Object merged = Internal.mergeMessage(mine, theirs);
|
|
- UnsafeUtil.putObject(message, offset, merged);
|
|
- setOneofPresent(message, number, pos);
|
|
- } else if (theirs != null) {
|
|
- UnsafeUtil.putObject(message, offset, theirs);
|
|
- setOneofPresent(message, number, pos);
|
|
+
|
|
+ final Schema fieldSchema = getMessageFieldSchema(pos);
|
|
+ if (!isOneofPresent(targetParent, number, pos)) {
|
|
+ if (!isMutable(source)) {
|
|
+ // Can safely share source if it is immutable
|
|
+ UNSAFE.putObject(targetParent, offset, source);
|
|
+ } else {
|
|
+ // Make a safety copy of theirs
|
|
+ final Object copyOfSource = fieldSchema.newInstance();
|
|
+ fieldSchema.mergeFrom(copyOfSource, source);
|
|
+ UNSAFE.putObject(targetParent, offset, copyOfSource);
|
|
+ }
|
|
+ setOneofPresent(targetParent, number, pos);
|
|
+ return;
|
|
}
|
|
+
|
|
+ // Sub-message is present, merge from source
|
|
+ Object target = UNSAFE.getObject(targetParent, offset);
|
|
+ if (!isMutable(target)) {
|
|
+ Object newInstance = fieldSchema.newInstance();
|
|
+ fieldSchema.mergeFrom(newInstance, target);
|
|
+ UNSAFE.putObject(targetParent, offset, newInstance);
|
|
+ target = newInstance;
|
|
+ }
|
|
+ fieldSchema.mergeFrom(target, source);
|
|
}
|
|
|
|
@Override
|
|
@@ -3853,6 +3891,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
if (extensionRegistry == null) {
|
|
throw new NullPointerException();
|
|
}
|
|
+ checkMutable(message);
|
|
mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry);
|
|
}
|
|
|
|
@@ -3889,6 +3928,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
}
|
|
unknownFields =
|
|
extensionSchema.parseExtension(
|
|
+ message,
|
|
reader,
|
|
extension,
|
|
extensionRegistry,
|
|
@@ -3955,21 +3995,10 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 9:
|
|
{ // MESSAGE:
|
|
- if (isFieldPresent(message, pos)) {
|
|
- Object mergedResult =
|
|
- Internal.mergeMessage(
|
|
- UnsafeUtil.getObject(message, offset(typeAndOffset)),
|
|
- reader.readMessageBySchemaWithCheck(
|
|
- (Schema<T>) getMessageFieldSchema(pos), extensionRegistry));
|
|
- UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult);
|
|
- } else {
|
|
- UnsafeUtil.putObject(
|
|
- message,
|
|
- offset(typeAndOffset),
|
|
- reader.readMessageBySchemaWithCheck(
|
|
- (Schema<T>) getMessageFieldSchema(pos), extensionRegistry));
|
|
- setFieldPresent(message, pos);
|
|
- }
|
|
+ final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos);
|
|
+ reader.mergeMessageField(
|
|
+ current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry);
|
|
+ storeMessageField(message, pos, current);
|
|
break;
|
|
}
|
|
case 10: // BYTES:
|
|
@@ -3990,7 +4019,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
} else {
|
|
unknownFields =
|
|
SchemaUtil.storeUnknownEnum(
|
|
- number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ message, number, enumValue, unknownFields, unknownFieldSchema);
|
|
}
|
|
break;
|
|
}
|
|
@@ -4012,21 +4041,10 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 17:
|
|
{ // GROUP:
|
|
- if (isFieldPresent(message, pos)) {
|
|
- Object mergedResult =
|
|
- Internal.mergeMessage(
|
|
- UnsafeUtil.getObject(message, offset(typeAndOffset)),
|
|
- reader.readGroupBySchemaWithCheck(
|
|
- (Schema<T>) getMessageFieldSchema(pos), extensionRegistry));
|
|
- UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult);
|
|
- } else {
|
|
- UnsafeUtil.putObject(
|
|
- message,
|
|
- offset(typeAndOffset),
|
|
- reader.readGroupBySchemaWithCheck(
|
|
- (Schema<T>) getMessageFieldSchema(pos), extensionRegistry));
|
|
- setFieldPresent(message, pos);
|
|
- }
|
|
+ final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos);
|
|
+ reader.mergeGroupField(
|
|
+ current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry);
|
|
+ storeMessageField(message, pos, current);
|
|
break;
|
|
}
|
|
case 18: // DOUBLE_LIST:
|
|
@@ -4089,6 +4107,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
reader.readEnumList(enumList);
|
|
unknownFields =
|
|
SchemaUtil.filterUnknownEnumList(
|
|
+ message,
|
|
number,
|
|
enumList,
|
|
getEnumFieldVerifier(pos),
|
|
@@ -4155,6 +4174,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
reader.readEnumList(enumList);
|
|
unknownFields =
|
|
SchemaUtil.filterUnknownEnumList(
|
|
+ message,
|
|
number,
|
|
enumList,
|
|
getEnumFieldVerifier(pos),
|
|
@@ -4235,24 +4255,15 @@ final class MessageSchema<T> implements Schema<T> {
|
|
readString(message, typeAndOffset, reader);
|
|
setOneofPresent(message, number, pos);
|
|
break;
|
|
- case 60: // ONEOF_MESSAGE:
|
|
- if (isOneofPresent(message, number, pos)) {
|
|
- Object mergedResult =
|
|
- Internal.mergeMessage(
|
|
- UnsafeUtil.getObject(message, offset(typeAndOffset)),
|
|
- reader.readMessageBySchemaWithCheck(
|
|
- getMessageFieldSchema(pos), extensionRegistry));
|
|
- UnsafeUtil.putObject(message, offset(typeAndOffset), mergedResult);
|
|
- } else {
|
|
- UnsafeUtil.putObject(
|
|
- message,
|
|
- offset(typeAndOffset),
|
|
- reader.readMessageBySchemaWithCheck(
|
|
- getMessageFieldSchema(pos), extensionRegistry));
|
|
- setFieldPresent(message, pos);
|
|
+ case 60:
|
|
+ { // ONEOF_MESSAGE:
|
|
+ final MessageLite current =
|
|
+ (MessageLite) mutableOneofMessageFieldForMerge(message, number, pos);
|
|
+ reader.mergeMessageField(
|
|
+ current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry);
|
|
+ storeOneofMessageField(message, number, pos, current);
|
|
+ break;
|
|
}
|
|
- setOneofPresent(message, number, pos);
|
|
- break;
|
|
case 61: // ONEOF_BYTES:
|
|
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes());
|
|
setOneofPresent(message, number, pos);
|
|
@@ -4272,7 +4283,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
} else {
|
|
unknownFields =
|
|
SchemaUtil.storeUnknownEnum(
|
|
- number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ message, number, enumValue, unknownFields, unknownFieldSchema);
|
|
}
|
|
break;
|
|
}
|
|
@@ -4296,17 +4307,19 @@ final class MessageSchema<T> implements Schema<T> {
|
|
message, offset(typeAndOffset), Long.valueOf(reader.readSInt64()));
|
|
setOneofPresent(message, number, pos);
|
|
break;
|
|
- case 68: // ONEOF_GROUP:
|
|
- UnsafeUtil.putObject(
|
|
- message,
|
|
- offset(typeAndOffset),
|
|
- reader.readGroupBySchemaWithCheck(getMessageFieldSchema(pos), extensionRegistry));
|
|
- setOneofPresent(message, number, pos);
|
|
- break;
|
|
+ case 68:
|
|
+ { // ONEOF_GROUP:
|
|
+ final MessageLite current =
|
|
+ (MessageLite) mutableOneofMessageFieldForMerge(message, number, pos);
|
|
+ reader.mergeGroupField(
|
|
+ current, (Schema<MessageLite>) getMessageFieldSchema(pos), extensionRegistry);
|
|
+ storeOneofMessageField(message, number, pos, current);
|
|
+ break;
|
|
+ }
|
|
default:
|
|
// Assume we've landed on an empty entry. Treat it as an unknown field.
|
|
if (unknownFields == null) {
|
|
- unknownFields = unknownFieldSchema.newBuilder();
|
|
+ unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
|
|
}
|
|
if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
|
|
return;
|
|
@@ -4333,7 +4346,8 @@ final class MessageSchema<T> implements Schema<T> {
|
|
} finally {
|
|
for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) {
|
|
unknownFields =
|
|
- filterMapUnknownEnumValues(message, intArray[i], unknownFields, unknownFieldSchema);
|
|
+ filterMapUnknownEnumValues(
|
|
+ message, intArray[i], unknownFields, unknownFieldSchema, message);
|
|
}
|
|
if (unknownFields != null) {
|
|
unknownFieldSchema.setBuilderToMessage(message, unknownFields);
|
|
@@ -4343,6 +4357,8 @@ final class MessageSchema<T> implements Schema<T> {
|
|
|
|
@SuppressWarnings("ReferenceEquality")
|
|
static UnknownFieldSetLite getMutableUnknownFields(Object message) {
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
|
|
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
|
unknownFields = UnknownFieldSetLite.newInstance();
|
|
@@ -4603,24 +4619,13 @@ final class MessageSchema<T> implements Schema<T> {
|
|
} else {
|
|
break;
|
|
}
|
|
- UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
|
|
- if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
|
- // filterUnknownEnumList() expects the unknownFields parameter to be mutable or null.
|
|
- // Since we don't know yet whether there exist unknown enum values, we'd better pass
|
|
- // null to it instead of allocating a mutable instance. This is also needed to be
|
|
- // consistent with the behavior of generated parser/builder.
|
|
- unknownFields = null;
|
|
- }
|
|
- unknownFields =
|
|
- SchemaUtil.filterUnknownEnumList(
|
|
- number,
|
|
- (ProtobufList<Integer>) list,
|
|
- getEnumFieldVerifier(bufferPosition),
|
|
- unknownFields,
|
|
- (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema);
|
|
- if (unknownFields != null) {
|
|
- ((GeneratedMessageLite) message).unknownFields = unknownFields;
|
|
- }
|
|
+ SchemaUtil.filterUnknownEnumList(
|
|
+ message,
|
|
+ number,
|
|
+ (ProtobufList<Integer>) list,
|
|
+ getEnumFieldVerifier(bufferPosition),
|
|
+ null,
|
|
+ (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema);
|
|
break;
|
|
case 33: // SINT32_LIST:
|
|
case 47: // SINT32_LIST_PACKED:
|
|
@@ -4774,20 +4779,11 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 60: // ONEOF_MESSAGE:
|
|
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
|
+ final Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition);
|
|
position =
|
|
- decodeMessageField(
|
|
- getMessageFieldSchema(bufferPosition), data, position, limit, registers);
|
|
- final Object oldValue =
|
|
- unsafe.getInt(message, oneofCaseOffset) == number
|
|
- ? unsafe.getObject(message, fieldOffset)
|
|
- : null;
|
|
- if (oldValue == null) {
|
|
- unsafe.putObject(message, fieldOffset, registers.object1);
|
|
- } else {
|
|
- unsafe.putObject(
|
|
- message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1));
|
|
- }
|
|
- unsafe.putInt(message, oneofCaseOffset, number);
|
|
+ mergeMessageField(
|
|
+ current, getMessageFieldSchema(bufferPosition), data, position, limit, registers);
|
|
+ storeOneofMessageField(message, number, bufferPosition, current);
|
|
}
|
|
break;
|
|
case 61: // ONEOF_BYTES:
|
|
@@ -4827,21 +4823,18 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 68: // ONEOF_GROUP:
|
|
if (wireType == WireFormat.WIRETYPE_START_GROUP) {
|
|
+ final Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition);
|
|
final int endTag = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
|
|
position =
|
|
- decodeGroupField(
|
|
- getMessageFieldSchema(bufferPosition), data, position, limit, endTag, registers);
|
|
- final Object oldValue =
|
|
- unsafe.getInt(message, oneofCaseOffset) == number
|
|
- ? unsafe.getObject(message, fieldOffset)
|
|
- : null;
|
|
- if (oldValue == null) {
|
|
- unsafe.putObject(message, fieldOffset, registers.object1);
|
|
- } else {
|
|
- unsafe.putObject(
|
|
- message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1));
|
|
- }
|
|
- unsafe.putInt(message, oneofCaseOffset, number);
|
|
+ mergeGroupField(
|
|
+ current,
|
|
+ getMessageFieldSchema(bufferPosition),
|
|
+ data,
|
|
+ position,
|
|
+ limit,
|
|
+ endTag,
|
|
+ registers);
|
|
+ storeOneofMessageField(message, number, bufferPosition, current);
|
|
}
|
|
break;
|
|
default:
|
|
@@ -4878,6 +4871,7 @@ final class MessageSchema<T> implements Schema<T> {
|
|
int parseProto2Message(
|
|
T message, byte[] data, int position, int limit, int endGroup, Registers registers)
|
|
throws IOException {
|
|
+ checkMutable(message);
|
|
final sun.misc.Unsafe unsafe = UNSAFE;
|
|
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
|
|
int currentPresenceField = 0;
|
|
@@ -4994,18 +4988,11 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 9: // MESSAGE
|
|
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
|
+ final Object current = mutableMessageFieldForMerge(message, pos);
|
|
position =
|
|
- decodeMessageField(
|
|
- getMessageFieldSchema(pos), data, position, limit, registers);
|
|
- if ((currentPresenceField & presenceMask) == 0) {
|
|
- unsafe.putObject(message, fieldOffset, registers.object1);
|
|
- } else {
|
|
- unsafe.putObject(
|
|
- message,
|
|
- fieldOffset,
|
|
- Internal.mergeMessage(
|
|
- unsafe.getObject(message, fieldOffset), registers.object1));
|
|
- }
|
|
+ mergeMessageField(
|
|
+ current, getMessageFieldSchema(pos), data, position, limit, registers);
|
|
+ storeMessageField(message, pos, current);
|
|
currentPresenceField |= presenceMask;
|
|
continue;
|
|
}
|
|
@@ -5054,20 +5041,18 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 17: // GROUP
|
|
if (wireType == WireFormat.WIRETYPE_START_GROUP) {
|
|
+ final Object current = mutableMessageFieldForMerge(message, pos);
|
|
final int endTag = (number << 3) | WireFormat.WIRETYPE_END_GROUP;
|
|
position =
|
|
- decodeGroupField(
|
|
- getMessageFieldSchema(pos), data, position, limit, endTag, registers);
|
|
- if ((currentPresenceField & presenceMask) == 0) {
|
|
- unsafe.putObject(message, fieldOffset, registers.object1);
|
|
- } else {
|
|
- unsafe.putObject(
|
|
- message,
|
|
- fieldOffset,
|
|
- Internal.mergeMessage(
|
|
- unsafe.getObject(message, fieldOffset), registers.object1));
|
|
- }
|
|
-
|
|
+ mergeGroupField(
|
|
+ current,
|
|
+ getMessageFieldSchema(pos),
|
|
+ data,
|
|
+ position,
|
|
+ limit,
|
|
+ endTag,
|
|
+ registers);
|
|
+ storeMessageField(message, pos, current);
|
|
currentPresenceField |= presenceMask;
|
|
continue;
|
|
}
|
|
@@ -5165,7 +5150,8 @@ final class MessageSchema<T> implements Schema<T> {
|
|
message,
|
|
intArray[i],
|
|
unknownFields,
|
|
- (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema);
|
|
+ (UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema,
|
|
+ message);
|
|
}
|
|
if (unknownFields != null) {
|
|
((UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite>) unknownFieldSchema)
|
|
@@ -5183,9 +5169,65 @@ final class MessageSchema<T> implements Schema<T> {
|
|
return position;
|
|
}
|
|
|
|
+ private Object mutableMessageFieldForMerge(T message, int pos) {
|
|
+ final Schema fieldSchema = getMessageFieldSchema(pos);
|
|
+ final long offset = offset(typeAndOffsetAt(pos));
|
|
+
|
|
+ // Field not present, create a new one
|
|
+ if (!isFieldPresent(message, pos)) {
|
|
+ return fieldSchema.newInstance();
|
|
+ }
|
|
+
|
|
+ // Field present, if mutable, ready to merge
|
|
+ final Object current = UNSAFE.getObject(message, offset);
|
|
+ if (isMutable(current)) {
|
|
+ return current;
|
|
+ }
|
|
+
|
|
+ // Field present but immutable, make a new mutable copy
|
|
+ final Object newMessage = fieldSchema.newInstance();
|
|
+ if (current != null) {
|
|
+ fieldSchema.mergeFrom(newMessage, current);
|
|
+ }
|
|
+ return newMessage;
|
|
+ }
|
|
+
|
|
+ private void storeMessageField(T message, int pos, Object field) {
|
|
+ UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field);
|
|
+ setFieldPresent(message, pos);
|
|
+ }
|
|
+
|
|
+ private Object mutableOneofMessageFieldForMerge(T message, int fieldNumber, int pos) {
|
|
+ final Schema fieldSchema = getMessageFieldSchema(pos);
|
|
+
|
|
+ // Field not present, create it and mark it present
|
|
+ if (!isOneofPresent(message, fieldNumber, pos)) {
|
|
+ return fieldSchema.newInstance();
|
|
+ }
|
|
+
|
|
+ // Field present, if mutable, ready to merge
|
|
+ final Object current = UNSAFE.getObject(message, offset(typeAndOffsetAt(pos)));
|
|
+ if (isMutable(current)) {
|
|
+ return current;
|
|
+ }
|
|
+
|
|
+ // Field present but immutable, make a new mutable copy
|
|
+ final Object newMessage = fieldSchema.newInstance();
|
|
+ if (current != null) {
|
|
+ fieldSchema.mergeFrom(newMessage, current);
|
|
+ }
|
|
+ return newMessage;
|
|
+ }
|
|
+
|
|
+ private void storeOneofMessageField(T message, int fieldNumber, int pos, Object field) {
|
|
+ UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field);
|
|
+ setOneofPresent(message, fieldNumber, pos);
|
|
+ }
|
|
+
|
|
/** Parses a proto3 message and returns the limit if parsing is successful. */
|
|
private int parseProto3Message(
|
|
T message, byte[] data, int position, int limit, Registers registers) throws IOException {
|
|
+ checkMutable(message);
|
|
final sun.misc.Unsafe unsafe = UNSAFE;
|
|
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
|
|
int currentPresenceField = 0;
|
|
@@ -5307,16 +5349,11 @@ final class MessageSchema<T> implements Schema<T> {
|
|
break;
|
|
case 9: // MESSAGE:
|
|
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
|
+ final Object current = mutableMessageFieldForMerge(message, pos);
|
|
position =
|
|
- decodeMessageField(
|
|
- getMessageFieldSchema(pos), data, position, limit, registers);
|
|
- final Object oldValue = unsafe.getObject(message, fieldOffset);
|
|
- if (oldValue == null) {
|
|
- unsafe.putObject(message, fieldOffset, registers.object1);
|
|
- } else {
|
|
- unsafe.putObject(
|
|
- message, fieldOffset, Internal.mergeMessage(oldValue, registers.object1));
|
|
- }
|
|
+ mergeMessageField(
|
|
+ current, getMessageFieldSchema(pos), data, position, limit, registers);
|
|
+ storeMessageField(message, pos, current);
|
|
currentPresenceField |= presenceMask;
|
|
continue;
|
|
}
|
|
@@ -5447,18 +5484,73 @@ final class MessageSchema<T> implements Schema<T> {
|
|
|
|
@Override
|
|
public void makeImmutable(T message) {
|
|
- // Make all repeated/map fields immutable.
|
|
- for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) {
|
|
- long offset = offset(typeAndOffsetAt(intArray[i]));
|
|
- Object mapField = UnsafeUtil.getObject(message, offset);
|
|
- if (mapField == null) {
|
|
- continue;
|
|
- }
|
|
- UnsafeUtil.putObject(message, offset, mapFieldSchema.toImmutable(mapField));
|
|
+ if (!isMutable(message)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
+ if (message instanceof GeneratedMessageLite) {
|
|
+ GeneratedMessageLite<?, ?> generatedMessage = ((GeneratedMessageLite<?, ?>) message);
|
|
+ generatedMessage.clearMemoizedSerializedSize();
|
|
+ generatedMessage.clearMemoizedHashCode();
|
|
+ generatedMessage.markImmutable();
|
|
}
|
|
- final int length = intArray.length;
|
|
- for (int i = repeatedFieldOffsetStart; i < length; i++) {
|
|
- listFieldSchema.makeImmutableListAt(message, intArray[i]);
|
|
+
|
|
+ final int bufferLength = buffer.length;
|
|
+ for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) {
|
|
+ final int typeAndOffset = typeAndOffsetAt(pos);
|
|
+ final long offset = offset(typeAndOffset);
|
|
+ switch (type(typeAndOffset)) {
|
|
+ case 17: // GROUP
|
|
+ case 9: // MESSAGE
|
|
+ if (isFieldPresent(message, pos)) {
|
|
+ getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
|
|
+ }
|
|
+ break;
|
|
+ case 18: // DOUBLE_LIST:
|
|
+ case 19: // FLOAT_LIST:
|
|
+ case 20: // INT64_LIST:
|
|
+ case 21: // UINT64_LIST:
|
|
+ case 22: // INT32_LIST:
|
|
+ case 23: // FIXED64_LIST:
|
|
+ case 24: // FIXED32_LIST:
|
|
+ case 25: // BOOL_LIST:
|
|
+ case 26: // STRING_LIST:
|
|
+ case 27: // MESSAGE_LIST:
|
|
+ case 28: // BYTES_LIST:
|
|
+ case 29: // UINT32_LIST:
|
|
+ case 30: // ENUM_LIST:
|
|
+ case 31: // SFIXED32_LIST:
|
|
+ case 32: // SFIXED64_LIST:
|
|
+ case 33: // SINT32_LIST:
|
|
+ case 34: // SINT64_LIST:
|
|
+ case 35: // DOUBLE_LIST_PACKED:
|
|
+ case 36: // FLOAT_LIST_PACKED:
|
|
+ case 37: // INT64_LIST_PACKED:
|
|
+ case 38: // UINT64_LIST_PACKED:
|
|
+ case 39: // INT32_LIST_PACKED:
|
|
+ case 40: // FIXED64_LIST_PACKED:
|
|
+ case 41: // FIXED32_LIST_PACKED:
|
|
+ case 42: // BOOL_LIST_PACKED:
|
|
+ case 43: // UINT32_LIST_PACKED:
|
|
+ case 44: // ENUM_LIST_PACKED:
|
|
+ case 45: // SFIXED32_LIST_PACKED:
|
|
+ case 46: // SFIXED64_LIST_PACKED:
|
|
+ case 47: // SINT32_LIST_PACKED:
|
|
+ case 48: // SINT64_LIST_PACKED:
|
|
+ case 49: // GROUP_LIST:
|
|
+ listFieldSchema.makeImmutableListAt(message, offset);
|
|
+ break;
|
|
+ case 50: // MAP:
|
|
+ {
|
|
+ Object mapField = UNSAFE.getObject(message, offset);
|
|
+ if (mapField != null) {
|
|
+ UNSAFE.putObject(message, offset, mapFieldSchema.toImmutable(mapField));
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
}
|
|
unknownFieldSchema.makeImmutable(message);
|
|
if (hasExtensions) {
|
|
@@ -5495,8 +5587,12 @@ final class MessageSchema<T> implements Schema<T> {
|
|
extensionRegistry);
|
|
}
|
|
|
|
- private final <UT, UB> UB filterMapUnknownEnumValues(
|
|
- Object message, int pos, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema) {
|
|
+ private <UT, UB> UB filterMapUnknownEnumValues(
|
|
+ Object message,
|
|
+ int pos,
|
|
+ UB unknownFields,
|
|
+ UnknownFieldSchema<UT, UB> unknownFieldSchema,
|
|
+ Object containerMessage) {
|
|
int fieldNumber = numberAt(pos);
|
|
long offset = offset(typeAndOffsetAt(pos));
|
|
Object mapField = UnsafeUtil.getObject(message, offset);
|
|
@@ -5511,25 +5607,32 @@ final class MessageSchema<T> implements Schema<T> {
|
|
// Filter unknown enum values.
|
|
unknownFields =
|
|
filterUnknownEnumMap(
|
|
- pos, fieldNumber, mapData, enumVerifier, unknownFields, unknownFieldSchema);
|
|
+ pos,
|
|
+ fieldNumber,
|
|
+ mapData,
|
|
+ enumVerifier,
|
|
+ unknownFields,
|
|
+ unknownFieldSchema,
|
|
+ containerMessage);
|
|
return unknownFields;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
- private final <K, V, UT, UB> UB filterUnknownEnumMap(
|
|
+ private <K, V, UT, UB> UB filterUnknownEnumMap(
|
|
int pos,
|
|
int number,
|
|
Map<K, V> mapData,
|
|
EnumVerifier enumVerifier,
|
|
UB unknownFields,
|
|
- UnknownFieldSchema<UT, UB> unknownFieldSchema) {
|
|
+ UnknownFieldSchema<UT, UB> unknownFieldSchema,
|
|
+ Object containerMessage) {
|
|
Metadata<K, V> metadata =
|
|
(Metadata<K, V>) mapFieldSchema.forMapMetadata(getMapFieldDefaultEntry(pos));
|
|
for (Iterator<Map.Entry<K, V>> it = mapData.entrySet().iterator(); it.hasNext(); ) {
|
|
Map.Entry<K, V> entry = it.next();
|
|
if (!enumVerifier.isInRange((Integer) entry.getValue())) {
|
|
if (unknownFields == null) {
|
|
- unknownFields = unknownFieldSchema.newBuilder();
|
|
+ unknownFields = unknownFieldSchema.getBuilderFromMessage(containerMessage);
|
|
}
|
|
int entrySize =
|
|
MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue());
|
|
@@ -5746,6 +5849,28 @@ final class MessageSchema<T> implements Schema<T> {
|
|
return value & OFFSET_MASK;
|
|
}
|
|
|
|
+ private static boolean isMutable(Object message) {
|
|
+ if (message == null) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
+ if (message instanceof GeneratedMessageLite<?, ?>) {
|
|
+ return ((GeneratedMessageLite<?, ?>) message).isMutable();
|
|
+ }
|
|
+
|
|
+ // For other types, we'll assume this is true because that's what was
|
|
+ // happening before we started checking.
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private static void checkMutable(Object message) {
|
|
+ if (!isMutable(message)) {
|
|
+ throw new IllegalArgumentException("Mutating immutable message: " + message);
|
|
+ }
|
|
+ }
|
|
+
|
|
private static <T> double doubleAt(T message, long offset) {
|
|
return UnsafeUtil.getDouble(message, offset);
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
|
|
index 187dc8b..eae93b9 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
|
|
@@ -61,7 +61,13 @@ final class MessageSetSchema<T> implements Schema<T> {
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
public T newInstance() {
|
|
- return (T) defaultInstance.newBuilderForType().buildPartial();
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
+ if (defaultInstance instanceof GeneratedMessageLite) {
|
|
+ return (T) ((GeneratedMessageLite<?, ?>) defaultInstance).newMutableInstance();
|
|
+ } else {
|
|
+ return (T) defaultInstance.newBuilderForType().buildPartial();
|
|
+ }
|
|
}
|
|
|
|
@Override
|
|
@@ -132,6 +138,8 @@ final class MessageSetSchema<T> implements Schema<T> {
|
|
public void mergeFrom(
|
|
T message, byte[] data, int position, int limit, ArrayDecoders.Registers registers)
|
|
throws IOException {
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
|
|
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
|
unknownFields = UnknownFieldSetLite.newInstance();
|
|
@@ -180,9 +188,12 @@ final class MessageSetSchema<T> implements Schema<T> {
|
|
if (wireType == WireFormat.WIRETYPE_VARINT) {
|
|
position = ArrayDecoders.decodeVarint32(data, position, registers);
|
|
typeId = registers.int1;
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and
|
|
+ // handle this better.
|
|
extension =
|
|
- (GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema
|
|
- .findExtensionByNumber(registers.extensionRegistry, defaultInstance, typeId);
|
|
+ (GeneratedMessageLite.GeneratedExtension<?, ?>)
|
|
+ extensionSchema.findExtensionByNumber(
|
|
+ registers.extensionRegistry, defaultInstance, typeId);
|
|
continue;
|
|
}
|
|
break;
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
|
|
index 9b92266..00cfe3b 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
|
|
@@ -33,7 +33,8 @@ package com.google.protobuf;
|
|
final class NewInstanceSchemaLite implements NewInstanceSchema {
|
|
@Override
|
|
public Object newInstance(Object defaultInstance) {
|
|
- return ((GeneratedMessageLite) defaultInstance)
|
|
- .dynamicMethod(GeneratedMessageLite.MethodToInvoke.NEW_MUTABLE_INSTANCE);
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
+ return ((GeneratedMessageLite<?, ?>) defaultInstance).newMutableInstance();
|
|
}
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/Reader.java b/java/core/src/main/java/com/google/protobuf/Reader.java
|
|
index 705096f..b99ee43 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/Reader.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/Reader.java
|
|
@@ -158,6 +158,14 @@ interface Reader {
|
|
<T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
throws IOException;
|
|
|
|
+ /** Read a message field from the wire format and merge the results into the given target. */
|
|
+ <T> void mergeMessageField(T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
+ throws IOException;
|
|
+
|
|
+ /** Read a group field from the wire format and merge the results into the given target. */
|
|
+ <T> void mergeGroupField(T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
|
|
+ throws IOException;
|
|
+
|
|
/**
|
|
* Reads and returns the next field of type {@code BYTES} and advances the reader to the next
|
|
* field.
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
|
|
index 4c8bb06..0e4c42c 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
|
|
@@ -59,6 +59,8 @@ final class SchemaUtil {
|
|
* GeneratedMessageLite}.
|
|
*/
|
|
public static void requireGeneratedMessage(Class<?> messageType) {
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
|
+ // better.
|
|
if (!GeneratedMessageLite.class.isAssignableFrom(messageType)
|
|
&& GENERATED_MESSAGE_CLASS != null
|
|
&& !GENERATED_MESSAGE_CLASS.isAssignableFrom(messageType)) {
|
|
@@ -808,6 +810,8 @@ final class SchemaUtil {
|
|
|
|
private static Class<?> getGeneratedMessageClass() {
|
|
try {
|
|
+ // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle
|
|
+ // this better.
|
|
return Class.forName("com.google.protobuf.GeneratedMessageV3");
|
|
} catch (Throwable e) {
|
|
return null;
|
|
@@ -901,6 +905,7 @@ final class SchemaUtil {
|
|
|
|
/** Filters unrecognized enum values in a list. */
|
|
static <UT, UB> UB filterUnknownEnumList(
|
|
+ Object containerMessage,
|
|
int number,
|
|
List<Integer> enumList,
|
|
EnumLiteMap<?> enumMap,
|
|
@@ -921,7 +926,9 @@ final class SchemaUtil {
|
|
}
|
|
++writePos;
|
|
} else {
|
|
- unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ unknownFields =
|
|
+ storeUnknownEnum(
|
|
+ containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
|
|
}
|
|
}
|
|
if (writePos != size) {
|
|
@@ -931,7 +938,9 @@ final class SchemaUtil {
|
|
for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) {
|
|
int enumValue = it.next();
|
|
if (enumMap.findValueByNumber(enumValue) == null) {
|
|
- unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ unknownFields =
|
|
+ storeUnknownEnum(
|
|
+ containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
|
|
it.remove();
|
|
}
|
|
}
|
|
@@ -941,6 +950,7 @@ final class SchemaUtil {
|
|
|
|
/** Filters unrecognized enum values in a list. */
|
|
static <UT, UB> UB filterUnknownEnumList(
|
|
+ Object containerMessage,
|
|
int number,
|
|
List<Integer> enumList,
|
|
EnumVerifier enumVerifier,
|
|
@@ -961,7 +971,9 @@ final class SchemaUtil {
|
|
}
|
|
++writePos;
|
|
} else {
|
|
- unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ unknownFields =
|
|
+ storeUnknownEnum(
|
|
+ containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
|
|
}
|
|
}
|
|
if (writePos != size) {
|
|
@@ -971,7 +983,9 @@ final class SchemaUtil {
|
|
for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) {
|
|
int enumValue = it.next();
|
|
if (!enumVerifier.isInRange(enumValue)) {
|
|
- unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
|
|
+ unknownFields =
|
|
+ storeUnknownEnum(
|
|
+ containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
|
|
it.remove();
|
|
}
|
|
}
|
|
@@ -981,9 +995,13 @@ final class SchemaUtil {
|
|
|
|
/** Stores an unrecognized enum value as an unknown value. */
|
|
static <UT, UB> UB storeUnknownEnum(
|
|
- int number, int enumValue, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema) {
|
|
+ Object containerMessage,
|
|
+ int number,
|
|
+ int enumValue,
|
|
+ UB unknownFields,
|
|
+ UnknownFieldSchema<UT, UB> unknownFieldSchema) {
|
|
if (unknownFields == null) {
|
|
- unknownFields = unknownFieldSchema.newBuilder();
|
|
+ unknownFields = unknownFieldSchema.getBuilderFromMessage(containerMessage);
|
|
}
|
|
unknownFieldSchema.addVarint(unknownFields, number, enumValue);
|
|
return unknownFields;
|
|
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 bbc0f8d..a5709cc 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
|
@@ -593,7 +593,7 @@ public final class TextFormat {
|
|
|
|
case MESSAGE:
|
|
case GROUP:
|
|
- print((Message) value, generator);
|
|
+ print((MessageOrBuilder) value, generator);
|
|
break;
|
|
}
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
|
|
index b2cb7be..37a14e2 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
|
|
@@ -388,7 +388,7 @@ public final class UnknownFieldSetLite {
|
|
// Package private for unsafe experimental runtime.
|
|
void storeField(int tag, Object value) {
|
|
checkMutable();
|
|
- ensureCapacity();
|
|
+ ensureCapacity(count + 1);
|
|
|
|
tags[count] = tag;
|
|
objects[count] = value;
|
|
@@ -396,13 +396,23 @@ public final class UnknownFieldSetLite {
|
|
}
|
|
|
|
/** Ensures that our arrays are long enough to store more metadata. */
|
|
- private void ensureCapacity() {
|
|
- if (count == tags.length) {
|
|
- int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
|
|
- int newLength = count + increment;
|
|
+ private void ensureCapacity(int minCapacity) {
|
|
+ if (minCapacity > this.tags.length) {
|
|
+ // Increase by at least 50%
|
|
+ int newCapacity = count + count / 2;
|
|
+
|
|
+ // Or new capacity if higher
|
|
+ if (newCapacity < minCapacity) {
|
|
+ newCapacity = minCapacity;
|
|
+ }
|
|
+
|
|
+ // And never less than MIN_CAPACITY
|
|
+ if (newCapacity < MIN_CAPACITY) {
|
|
+ newCapacity = MIN_CAPACITY;
|
|
+ }
|
|
|
|
- tags = Arrays.copyOf(tags, newLength);
|
|
- objects = Arrays.copyOf(objects, newLength);
|
|
+ this.tags = Arrays.copyOf(this.tags, newCapacity);
|
|
+ this.objects = Arrays.copyOf(this.objects, newCapacity);
|
|
}
|
|
}
|
|
|
|
@@ -487,4 +497,18 @@ public final class UnknownFieldSetLite {
|
|
}
|
|
return this;
|
|
}
|
|
+
|
|
+ UnknownFieldSetLite mergeFrom(UnknownFieldSetLite other) {
|
|
+ if (other.equals(getDefaultInstance())) {
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ checkMutable();
|
|
+ int newCount = this.count + other.count;
|
|
+ ensureCapacity(newCount);
|
|
+ System.arraycopy(other.tags, 0, tags, this.count, other.count);
|
|
+ System.arraycopy(other.objects, 0, objects, this.count, other.count);
|
|
+ this.count = newCount;
|
|
+ return this;
|
|
+ }
|
|
}
|
|
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
|
|
index ffd7232..2cfdeca 100644
|
|
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
|
|
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
|
|
@@ -122,10 +122,14 @@ class UnknownFieldSetLiteSchema
|
|
}
|
|
|
|
@Override
|
|
- UnknownFieldSetLite merge(UnknownFieldSetLite message, UnknownFieldSetLite other) {
|
|
- return other.equals(UnknownFieldSetLite.getDefaultInstance())
|
|
- ? message
|
|
- : UnknownFieldSetLite.mutableCopyOf(message, other);
|
|
+ UnknownFieldSetLite merge(UnknownFieldSetLite target, UnknownFieldSetLite source) {
|
|
+ if (UnknownFieldSetLite.getDefaultInstance().equals(source)) {
|
|
+ return target;
|
|
+ }
|
|
+ if (UnknownFieldSetLite.getDefaultInstance().equals(target)) {
|
|
+ return UnknownFieldSetLite.mutableCopyOf(target, source);
|
|
+ }
|
|
+ return target.mergeFrom(source);
|
|
}
|
|
|
|
@Override
|
|
diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
|
|
index 140df72..7481b69 100644
|
|
--- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
|
|
+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
|
|
@@ -49,15 +49,6 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
|
|
import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
|
|
import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite;
|
|
import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
|
|
-import map_lite_test.MapTestProto.TestMap;
|
|
-import map_lite_test.MapTestProto.TestMap.MessageValue;
|
|
-import protobuf_unittest.NestedExtensionLite;
|
|
-import protobuf_unittest.NonNestedExtensionLite;
|
|
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
|
|
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
|
|
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
|
|
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
|
|
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
@@ -69,6 +60,15 @@ import java.util.Arrays;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import junit.framework.TestCase;
|
|
+import map_lite_test.MapTestProto.TestMap;
|
|
+import map_lite_test.MapTestProto.TestMap.MessageValue;
|
|
+import protobuf_unittest.NestedExtensionLite;
|
|
+import protobuf_unittest.NonNestedExtensionLite;
|
|
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
|
|
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
|
|
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
|
|
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
|
|
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
|
|
|
|
/**
|
|
* Test lite runtime.
|
|
@@ -181,16 +181,24 @@ public class LiteTest extends TestCase {
|
|
TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
|
|
|
|
// Test serialized size is memoized
|
|
- message.memoizedSerializedSize = -1;
|
|
+ assertEquals(
|
|
+ GeneratedMessageLite.UNINITIALIZED_SERIALIZED_SIZE,
|
|
+ message.getMemoizedSerializedSize());
|
|
int size = message.getSerializedSize();
|
|
assertTrue(size > 0);
|
|
- assertEquals(size, message.memoizedSerializedSize);
|
|
+ assertEquals(size, message.getMemoizedSerializedSize());
|
|
+ message.clearMemoizedSerializedSize();
|
|
+ assertEquals(
|
|
+ GeneratedMessageLite.UNINITIALIZED_SERIALIZED_SIZE,
|
|
+ message.getMemoizedSerializedSize());
|
|
|
|
// Test hashCode is memoized
|
|
- assertEquals(0, message.memoizedHashCode);
|
|
+ assertTrue(message.hashCodeIsNotMemoized());
|
|
int hashCode = message.hashCode();
|
|
- assertTrue(hashCode != 0);
|
|
- assertEquals(hashCode, message.memoizedHashCode);
|
|
+ assertFalse(message.hashCodeIsNotMemoized());
|
|
+ assertEquals(hashCode, message.getMemoizedHashCode());
|
|
+ message.clearMemoizedHashCode();
|
|
+ assertTrue(message.hashCodeIsNotMemoized());
|
|
|
|
// Test isInitialized is memoized
|
|
Field memo = message.getClass().getDeclaredField("memoizedIsInitialized");
|
|
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 352376e..2aa0916 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
|
|
@@ -35,6 +35,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
|
import com.google.protobuf.Descriptors.Descriptor;
|
|
import com.google.protobuf.Descriptors.FieldDescriptor;
|
|
import com.google.protobuf.FieldMask;
|
|
+import com.google.protobuf.GeneratedMessage;
|
|
import com.google.protobuf.Message;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
@@ -304,9 +305,12 @@ final class FieldMaskTree {
|
|
// so we don't create unnecessary empty messages.
|
|
continue;
|
|
}
|
|
- String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
|
|
- Message.Builder childBuilder = ((Message) destination.getField(field)).toBuilder();
|
|
- merge(entry.getValue(), childPath, (Message) source.getField(field), childBuilder, options);
|
|
+ // This is a mess because of java proto API 1 still hanging around.
|
|
+ Message.Builder childBuilder =
|
|
+ destination instanceof GeneratedMessage.Builder
|
|
+ ? destination.getFieldBuilder(field)
|
|
+ : ((Message) destination.getField(field)).toBuilder();
|
|
+ merge(entry.getValue(), path, (Message) source.getField(field), childBuilder, options);
|
|
destination.setField(field, childBuilder.buildPartial());
|
|
continue;
|
|
}
|
|
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
|
|
index d96ac7d..15626f9 100644
|
|
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
|
|
@@ -110,13 +110,6 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
|
|
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
|
|
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
|
|
|
|
- // For repeated fields, one bit is used for whether the array is immutable
|
|
- // in the parsing constructor.
|
|
- (*variables)["get_mutable_bit_parser"] =
|
|
- GenerateGetBitMutableLocal(builderBitIndex);
|
|
- (*variables)["set_mutable_bit_parser"] =
|
|
- GenerateSetBitMutableLocal(builderBitIndex);
|
|
-
|
|
(*variables)["get_has_field_bit_from_local"] =
|
|
GenerateGetBitFromLocal(builderBitIndex);
|
|
(*variables)["set_has_field_bit_to_local"] =
|
|
@@ -314,32 +307,26 @@ void ImmutableEnumFieldGenerator::GenerateBuildingCode(
|
|
printer->Print(variables_, "result.$name$_ = $name$_;\n");
|
|
}
|
|
|
|
-void ImmutableEnumFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
if (SupportUnknownEnumValue(descriptor_->file())) {
|
|
printer->Print(variables_,
|
|
- "int rawValue = input.readEnum();\n"
|
|
- "$set_has_field_bit_message$\n"
|
|
- "$name$_ = rawValue;\n");
|
|
+ "$name$_ = input.readEnum();\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
} else {
|
|
printer->Print(variables_,
|
|
- "int rawValue = input.readEnum();\n"
|
|
- " @SuppressWarnings(\"deprecation\")\n"
|
|
- "$type$ value = $type$.$for_number$(rawValue);\n"
|
|
- "if (value == null) {\n"
|
|
- " unknownFields.mergeVarintField($number$, rawValue);\n"
|
|
+ "int tmpRaw = input.readEnum();\n"
|
|
+ "$type$ tmpValue =\n"
|
|
+ " $type$.forNumber(tmpRaw);\n"
|
|
+ "if (tmpValue == null) {\n"
|
|
+ " mergeUnknownVarintField($number$, tmpRaw);\n"
|
|
"} else {\n"
|
|
- " $set_has_field_bit_message$\n"
|
|
- " $name$_ = rawValue;\n"
|
|
+ " $name$_ = tmpRaw;\n"
|
|
+ " $set_has_field_bit_builder$\n"
|
|
"}\n");
|
|
}
|
|
}
|
|
|
|
-void ImmutableEnumFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- // noop for enums
|
|
-}
|
|
-
|
|
void ImmutableEnumFieldGenerator::GenerateSerializationCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
@@ -502,6 +489,11 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|
printer->Annotate("{", "}", descriptor_);
|
|
}
|
|
|
|
+void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearCode(
|
|
+ io::Printer* printer) const {
|
|
+ // No-op: Enum fields in oneofs are correctly cleared by clearing the oneof
|
|
+}
|
|
+
|
|
void ImmutableEnumOneofFieldGenerator::GenerateBuildingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
@@ -522,7 +514,7 @@ void ImmutableEnumOneofFieldGenerator::GenerateMergingCode(
|
|
}
|
|
}
|
|
|
|
-void ImmutableEnumOneofFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableEnumOneofFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
if (SupportUnknownEnumValue(descriptor_->file())) {
|
|
printer->Print(variables_,
|
|
@@ -532,10 +524,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateParsingCode(
|
|
} else {
|
|
printer->Print(variables_,
|
|
"int rawValue = input.readEnum();\n"
|
|
- "@SuppressWarnings(\"deprecation\")\n"
|
|
- "$type$ value = $type$.$for_number$(rawValue);\n"
|
|
+ "$type$ value =\n"
|
|
+ " $type$.forNumber(rawValue);\n"
|
|
"if (value == null) {\n"
|
|
- " unknownFields.mergeVarintField($number$, rawValue);\n"
|
|
+ " mergeUnknownVarintField($number$, rawValue);\n"
|
|
"} else {\n"
|
|
" $set_oneof_case_message$;\n"
|
|
" $oneof_name$_ = rawValue;\n"
|
|
@@ -914,36 +906,29 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuildingCode(
|
|
"result.$name$_ = $name$_;\n");
|
|
}
|
|
|
|
-void RepeatedImmutableEnumFieldGenerator::GenerateParsingCode(
|
|
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
// Read and store the enum
|
|
if (SupportUnknownEnumValue(descriptor_->file())) {
|
|
printer->Print(variables_,
|
|
- "int rawValue = input.readEnum();\n"
|
|
- "if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- "}\n"
|
|
- "$name$_.add(rawValue);\n");
|
|
+ "int tmpRaw = input.readEnum();\n"
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "$name$_.add(tmpRaw);\n");
|
|
} else {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "int rawValue = input.readEnum();\n"
|
|
- "@SuppressWarnings(\"deprecation\")\n"
|
|
- "$type$ value = $type$.$for_number$(rawValue);\n"
|
|
- "if (value == null) {\n"
|
|
- " unknownFields.mergeVarintField($number$, rawValue);\n"
|
|
- "} else {\n"
|
|
- " if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- " }\n"
|
|
- " $name$_.add(rawValue);\n"
|
|
- "}\n");
|
|
+ printer->Print(variables_,
|
|
+ "int tmpRaw = input.readEnum();\n"
|
|
+ "$type$ tmpValue =\n"
|
|
+ " $type$.forNumber(tmpRaw);\n"
|
|
+ "if (tmpValue == null) {\n"
|
|
+ " mergeUnknownVarintField($number$, tmpRaw);\n"
|
|
+ "} else {\n"
|
|
+ " ensure$capitalized_name$IsMutable();\n"
|
|
+ " $name$_.add(tmpRaw);\n"
|
|
+ "}\n");
|
|
}
|
|
}
|
|
|
|
-void RepeatedImmutableEnumFieldGenerator::GenerateParsingCodeFromPacked(
|
|
+void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCodeFromPacked(
|
|
io::Printer* printer) const {
|
|
// Wrap GenerateParsingCode's contents with a while loop.
|
|
|
|
@@ -953,7 +938,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateParsingCodeFromPacked(
|
|
"while(input.getBytesUntilLimit() > 0) {\n");
|
|
printer->Indent();
|
|
|
|
- GenerateParsingCode(printer);
|
|
+ GenerateBuilderParsingCode(printer);
|
|
|
|
printer->Outdent();
|
|
printer->Print(variables_,
|
|
@@ -961,15 +946,6 @@ void RepeatedImmutableEnumFieldGenerator::GenerateParsingCodeFromPacked(
|
|
"input.popLimit(oldLimit);\n");
|
|
}
|
|
|
|
-void RepeatedImmutableEnumFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "if ($get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
|
|
- "}\n");
|
|
-}
|
|
-
|
|
void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode(
|
|
io::Printer* printer) const {
|
|
if (descriptor_->is_packed()) {
|
|
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
|
|
index 95c7db5..318e013 100644
|
|
--- a/src/google/protobuf/compiler/java/java_enum_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
|
|
@@ -64,24 +64,24 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
|
|
|
|
// implements ImmutableFieldGenerator
|
|
// ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
protected:
|
|
const FieldDescriptor* descriptor_;
|
|
@@ -99,15 +99,16 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
|
|
Context* context);
|
|
~ImmutableEnumOneofFieldGenerator();
|
|
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
|
|
private:
|
|
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator);
|
|
@@ -121,25 +122,26 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
|
|
~RepeatedImmutableEnumFieldGenerator();
|
|
|
|
// implements ImmutableFieldGenerator ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCodeFromPacked(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
private:
|
|
const FieldDescriptor* descriptor_;
|
|
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
|
|
index 2f775a6..229b3b3 100644
|
|
--- a/src/google/protobuf/compiler/java/java_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_field.cc
|
|
@@ -185,7 +185,7 @@ static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
|
|
// but this method should be overridden.
|
|
// - This FieldGenerator doesn't support packing, and this method
|
|
// should never have been called.
|
|
- GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
|
|
+ GOOGLE_LOG(FATAL) << "GenerateBuilderParsingCodeFromPacked() "
|
|
<< "called on field generator that does not support packing.";
|
|
}
|
|
|
|
@@ -193,7 +193,7 @@ static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
|
|
|
|
ImmutableFieldGenerator::~ImmutableFieldGenerator() {}
|
|
|
|
-void ImmutableFieldGenerator::GenerateParsingCodeFromPacked(
|
|
+void ImmutableFieldGenerator::GenerateBuilderParsingCodeFromPacked(
|
|
io::Printer* printer) const {
|
|
ReportUnexpectedPackedFieldsCall(printer);
|
|
}
|
|
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
|
|
index 9d04dc8..7e0cd77 100644
|
|
--- a/src/google/protobuf/compiler/java/java_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_field.h
|
|
@@ -76,9 +76,8 @@ class ImmutableFieldGenerator {
|
|
virtual void GenerateBuilderClearCode(io::Printer* printer) const = 0;
|
|
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
|
|
virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
|
|
- virtual void GenerateParsingCode(io::Printer* printer) const = 0;
|
|
- virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
|
- virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0;
|
|
+ virtual void GenerateBuilderParsingCode(io::Printer* printer) const = 0;
|
|
+ virtual void GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const;
|
|
virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
|
|
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
|
|
virtual void GenerateFieldBuilderInitializationCode(
|
|
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
|
|
index 5db199d..1fb8f1e 100644
|
|
--- a/src/google/protobuf/compiler/java/java_map_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
|
|
@@ -138,13 +138,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
|
|
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
|
|
(*variables)["on_changed"] = "onChanged();";
|
|
|
|
- // For repeated fields, one bit is used for whether the array is immutable
|
|
- // in the parsing constructor.
|
|
- (*variables)["get_mutable_bit_parser"] =
|
|
- GenerateGetBitMutableLocal(builderBitIndex);
|
|
- (*variables)["set_mutable_bit_parser"] =
|
|
- GenerateSetBitMutableLocal(builderBitIndex);
|
|
-
|
|
(*variables)["default_entry"] =
|
|
(*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry";
|
|
(*variables)["map_field_parameter"] = (*variables)["default_entry"];
|
|
@@ -681,27 +674,19 @@ void ImmutableMapFieldGenerator::GenerateBuildingCode(
|
|
"result.$name$_.makeImmutable();\n");
|
|
}
|
|
|
|
-void ImmutableMapFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
- printer->Print(variables_,
|
|
- "if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = com.google.protobuf.MapField.newMapField(\n"
|
|
- " $map_field_parameter$);\n"
|
|
- " $set_mutable_bit_parser$;\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<$type_parameters$>\n"
|
|
- "$name$__ = $default_entry$.getParserForType().parseFrom(bytes);\n");
|
|
- printer->Print(
|
|
- variables_,
|
|
+ "$name$__ = $default_entry$.getParserForType().parseFrom(bytes);\n"
|
|
"if ($value_enum_type$.forNumber($name$__.getValue()) == null) {\n"
|
|
- " unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
|
|
+ " mergeUnknownLengthDelimitedField($number$, bytes);\n"
|
|
"} else {\n"
|
|
- " $name$_.getMutableMap().put(\n"
|
|
+ " internalGetMutable$capitalized_name$().getMutableMap().put(\n"
|
|
" $name$__.getKey(), $name$__.getValue());\n"
|
|
"}\n");
|
|
} else {
|
|
@@ -710,16 +695,11 @@ void ImmutableMapFieldGenerator::GenerateParsingCode(
|
|
"com.google.protobuf.MapEntry<$type_parameters$>\n"
|
|
"$name$__ = input.readMessage(\n"
|
|
" $default_entry$.getParserForType(), extensionRegistry);\n"
|
|
- "$name$_.getMutableMap().put(\n"
|
|
+ "internalGetMutable$capitalized_name$().getMutableMap().put(\n"
|
|
" $name$__.getKey(), $name$__.getValue());\n");
|
|
}
|
|
}
|
|
|
|
-void ImmutableMapFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- // Nothing to do here.
|
|
-}
|
|
-
|
|
void ImmutableMapFieldGenerator::GenerateSerializationCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
|
|
index 2ff1f76..4e46222 100644
|
|
--- a/src/google/protobuf/compiler/java/java_map_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_map_field.h
|
|
@@ -46,23 +46,23 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
|
|
~ImmutableMapFieldGenerator();
|
|
|
|
// implements ImmutableFieldGenerator ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
std::string GetBoxedType() const;
|
|
|
|
private:
|
|
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
|
|
index 6623595..43c325a 100644
|
|
--- a/src/google/protobuf/compiler/java/java_message.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_message.cc
|
|
@@ -51,6 +51,7 @@
|
|
#include <google/protobuf/descriptor.pb.h>
|
|
#include <google/protobuf/io/coded_stream.h>
|
|
#include <google/protobuf/io/printer.h>
|
|
+#include <google/protobuf/descriptor.h>
|
|
#include <google/protobuf/wire_format.h>
|
|
#include <google/protobuf/stubs/strutil.h>
|
|
#include <google/protobuf/stubs/substitute.h>
|
|
@@ -367,6 +368,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
|
|
"}\n"
|
|
"\n");
|
|
|
|
+ // TODO(b/248149118): Remove this superfluous override.
|
|
printer->Print(
|
|
"@java.lang.Override\n"
|
|
"public final com.google.protobuf.UnknownFieldSet\n"
|
|
@@ -374,10 +376,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
|
|
" return this.unknownFields;\n"
|
|
"}\n");
|
|
|
|
- if (context_->HasGeneratedMethods(descriptor_)) {
|
|
- GenerateParsingConstructor(printer);
|
|
- }
|
|
-
|
|
GenerateDescriptorMethods(printer);
|
|
|
|
// Nested types
|
|
@@ -624,9 +622,9 @@ void ImmutableMessageGenerator::GenerateMessageSerializationMethods(
|
|
}
|
|
|
|
if (descriptor_->options().message_set_wire_format()) {
|
|
- printer->Print("unknownFields.writeAsMessageSetTo(output);\n");
|
|
+ printer->Print("getUnknownFields().writeAsMessageSetTo(output);\n");
|
|
} else {
|
|
- printer->Print("unknownFields.writeTo(output);\n");
|
|
+ printer->Print("getUnknownFields().writeTo(output);\n");
|
|
}
|
|
|
|
printer->Outdent();
|
|
@@ -655,9 +653,10 @@ void ImmutableMessageGenerator::GenerateMessageSerializationMethods(
|
|
}
|
|
|
|
if (descriptor_->options().message_set_wire_format()) {
|
|
- printer->Print("size += unknownFields.getSerializedSizeAsMessageSet();\n");
|
|
+ printer->Print(
|
|
+ "size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
|
|
} else {
|
|
- printer->Print("size += unknownFields.getSerializedSize();\n");
|
|
+ printer->Print("size += getUnknownFields().getSerializedSize();\n");
|
|
}
|
|
|
|
printer->Print(
|
|
@@ -1054,7 +1053,8 @@ void ImmutableMessageGenerator::GenerateEqualsAndHashCode(
|
|
// false for non-canonical ordering when running in LITE_RUNTIME but it's
|
|
// the best we can do.
|
|
printer->Print(
|
|
- "if (!unknownFields.equals(other.unknownFields)) return false;\n");
|
|
+ "if (!getUnknownFields().equals(other.getUnknownFields())) return "
|
|
+ "false;\n");
|
|
if (descriptor_->extension_range_count() > 0) {
|
|
printer->Print(
|
|
"if (!getExtensionFields().equals(other.getExtensionFields()))\n"
|
|
@@ -1128,7 +1128,7 @@ void ImmutableMessageGenerator::GenerateEqualsAndHashCode(
|
|
printer->Print("hash = hashFields(hash, getExtensionFields());\n");
|
|
}
|
|
|
|
- printer->Print("hash = (29 * hash) + unknownFields.hashCode();\n");
|
|
+ printer->Print("hash = (29 * hash) + getUnknownFields().hashCode();\n");
|
|
printer->Print(
|
|
"memoizedHashCode = hash;\n"
|
|
"return hash;\n");
|
|
@@ -1153,186 +1153,33 @@ void ImmutableMessageGenerator::GenerateExtensionRegistrationCode(
|
|
}
|
|
}
|
|
|
|
-// ===================================================================
|
|
-void ImmutableMessageGenerator::GenerateParsingConstructor(
|
|
- io::Printer* printer) {
|
|
- std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
|
|
- SortFieldsByNumber(descriptor_));
|
|
-
|
|
- printer->Print(
|
|
- "private $classname$(\n"
|
|
- " com.google.protobuf.CodedInputStream input,\n"
|
|
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
|
|
- " throws com.google.protobuf.InvalidProtocolBufferException {\n",
|
|
- "classname", descriptor_->name());
|
|
- printer->Indent();
|
|
-
|
|
- // Initialize all fields to default.
|
|
- printer->Print(
|
|
- "this();\n"
|
|
- "if (extensionRegistry == null) {\n"
|
|
- " throw new java.lang.NullPointerException();\n"
|
|
- "}\n");
|
|
-
|
|
- // Use builder bits to track mutable repeated fields.
|
|
- int totalBuilderBits = 0;
|
|
- for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
- const ImmutableFieldGenerator& field =
|
|
- field_generators_.get(descriptor_->field(i));
|
|
- totalBuilderBits += field.GetNumBitsForBuilder();
|
|
- }
|
|
- int totalBuilderInts = (totalBuilderBits + 31) / 32;
|
|
- for (int i = 0; i < totalBuilderInts; i++) {
|
|
- printer->Print("int mutable_$bit_field_name$ = 0;\n", "bit_field_name",
|
|
- GetBitFieldName(i));
|
|
- }
|
|
-
|
|
- printer->Print(
|
|
- "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
|
|
- " com.google.protobuf.UnknownFieldSet.newBuilder();\n");
|
|
-
|
|
- printer->Print("try {\n");
|
|
- printer->Indent();
|
|
-
|
|
- printer->Print(
|
|
- "boolean done = false;\n"
|
|
- "while (!done) {\n");
|
|
- printer->Indent();
|
|
-
|
|
- printer->Print(
|
|
- "int tag = input.readTag();\n"
|
|
- "switch (tag) {\n");
|
|
- printer->Indent();
|
|
-
|
|
- printer->Print(
|
|
- "case 0:\n" // zero signals EOF / limit reached
|
|
- " done = true;\n"
|
|
- " break;\n");
|
|
-
|
|
- for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
- const FieldDescriptor* field = sorted_fields[i];
|
|
- uint32 tag = WireFormatLite::MakeTag(
|
|
- field->number(), WireFormat::WireTypeForFieldType(field->type()));
|
|
-
|
|
- printer->Print("case $tag$: {\n", "tag",
|
|
- StrCat(static_cast<int32>(tag)));
|
|
- printer->Indent();
|
|
-
|
|
- field_generators_.get(field).GenerateParsingCode(printer);
|
|
-
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
- " break;\n"
|
|
- "}\n");
|
|
-
|
|
- if (field->is_packable()) {
|
|
- // To make packed = true wire compatible, we generate parsing code from a
|
|
- // packed version of this field regardless of field->options().packed().
|
|
- uint32 packed_tag = WireFormatLite::MakeTag(
|
|
- field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
|
- printer->Print("case $tag$: {\n", "tag",
|
|
- StrCat(static_cast<int32>(packed_tag)));
|
|
- printer->Indent();
|
|
-
|
|
- field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
|
|
-
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
- " break;\n"
|
|
- "}\n");
|
|
- }
|
|
- }
|
|
-
|
|
- printer->Print(
|
|
- "default: {\n"
|
|
- " if (!parseUnknownField(\n"
|
|
- " input, unknownFields, extensionRegistry, tag)) {\n"
|
|
- " done = true;\n" // it's an endgroup tag
|
|
- " }\n"
|
|
- " break;\n"
|
|
- "}\n");
|
|
-
|
|
- printer->Outdent();
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
- " }\n" // switch (tag)
|
|
- "}\n"); // while (!done)
|
|
-
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
- "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
|
|
- " throw e.setUnfinishedMessage(this);\n"
|
|
- "} catch (java.io.IOException e) {\n"
|
|
- " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
|
|
- " e).setUnfinishedMessage(this);\n"
|
|
- "} finally {\n");
|
|
- printer->Indent();
|
|
-
|
|
- // Make repeated field list immutable.
|
|
- for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
- const FieldDescriptor* field = sorted_fields[i];
|
|
- field_generators_.get(field).GenerateParsingDoneCode(printer);
|
|
- }
|
|
-
|
|
- // Make unknown fields immutable.
|
|
- printer->Print("this.unknownFields = unknownFields.build();\n");
|
|
-
|
|
- // Make extensions immutable.
|
|
- printer->Print("makeExtensionsImmutable();\n");
|
|
-
|
|
- printer->Outdent();
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
- " }\n" // finally
|
|
- "}\n");
|
|
-}
|
|
-
|
|
// ===================================================================
|
|
void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
|
|
printer->Print(
|
|
"$visibility$ static final com.google.protobuf.Parser<$classname$>\n"
|
|
- " PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n",
|
|
- "visibility",
|
|
- ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public"
|
|
- : "private",
|
|
- "classname", descriptor_->name());
|
|
- printer->Indent();
|
|
- printer->Print(
|
|
- "@java.lang.Override\n"
|
|
- "public $classname$ parsePartialFrom(\n"
|
|
- " com.google.protobuf.CodedInputStream input,\n"
|
|
- " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
|
|
- " throws com.google.protobuf.InvalidProtocolBufferException {\n",
|
|
- "classname", descriptor_->name());
|
|
- if (context_->HasGeneratedMethods(descriptor_)) {
|
|
- printer->Print(" return new $classname$(input, extensionRegistry);\n",
|
|
- "classname", descriptor_->name());
|
|
- } else {
|
|
- // When parsing constructor isn't generated, use builder to parse
|
|
- // messages. Note, will fallback to use reflection based mergeFieldFrom()
|
|
- // in AbstractMessage.Builder.
|
|
- printer->Indent();
|
|
- printer->Print(
|
|
- "Builder builder = newBuilder();\n"
|
|
- "try {\n"
|
|
- " builder.mergeFrom(input, extensionRegistry);\n"
|
|
- "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
|
|
- " throw e.setUnfinishedMessage(builder.buildPartial());\n"
|
|
- "} catch (java.io.IOException e) {\n"
|
|
- " throw new com.google.protobuf.InvalidProtocolBufferException(\n"
|
|
- " e.getMessage()).setUnfinishedMessage(\n"
|
|
- " builder.buildPartial());\n"
|
|
- "}\n"
|
|
- "return builder.buildPartial();\n");
|
|
- printer->Outdent();
|
|
- }
|
|
- printer->Print("}\n");
|
|
- printer->Outdent();
|
|
- printer->Print(
|
|
+ " PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n"
|
|
+ " @java.lang.Override\n"
|
|
+ " public $classname$ parsePartialFrom(\n"
|
|
+ " com.google.protobuf.CodedInputStream input,\n"
|
|
+ " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
|
|
+ " throws com.google.protobuf.InvalidProtocolBufferException {\n"
|
|
+ " Builder builder = newBuilder();\n"
|
|
+ " try {\n"
|
|
+ " builder.mergeFrom(input, extensionRegistry);\n"
|
|
+ " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
|
|
+ " throw e.setUnfinishedMessage(builder.buildPartial());\n"
|
|
+ " } catch (com.google.protobuf.UninitializedMessageException e) {\n"
|
|
+ " throw "
|
|
+ "e.asInvalidProtocolBufferException().setUnfinishedMessage(builder."
|
|
+ "buildPartial());\n"
|
|
+ " } catch (java.io.IOException e) {\n"
|
|
+ " throw new com.google.protobuf.InvalidProtocolBufferException(e)\n"
|
|
+ " .setUnfinishedMessage(builder.buildPartial());\n"
|
|
+ " }\n"
|
|
+ " return builder.buildPartial();\n"
|
|
+ " }\n"
|
|
"};\n"
|
|
- "\n");
|
|
-
|
|
- printer->Print(
|
|
+ "\n"
|
|
"public static com.google.protobuf.Parser<$classname$> parser() {\n"
|
|
" return PARSER;\n"
|
|
"}\n"
|
|
@@ -1342,6 +1189,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
|
|
" return PARSER;\n"
|
|
"}\n"
|
|
"\n",
|
|
+ "visibility",
|
|
+ ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public"
|
|
+ : "private",
|
|
"classname", descriptor_->name());
|
|
}
|
|
|
|
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
|
|
index 320852b..24ea648 100644
|
|
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
|
|
@@ -58,6 +58,9 @@ namespace protobuf {
|
|
namespace compiler {
|
|
namespace java {
|
|
|
|
+using internal::WireFormat;
|
|
+using internal::WireFormatLite;
|
|
+
|
|
namespace {
|
|
std::string MapValueImmutableClassdName(const Descriptor* descriptor,
|
|
ClassNameResolver* name_resolver) {
|
|
@@ -285,43 +288,63 @@ void MessageBuilderGenerator::GenerateDescriptorMethods(io::Printer* printer) {
|
|
|
|
void MessageBuilderGenerator::GenerateCommonBuilderMethods(
|
|
io::Printer* printer) {
|
|
+ // Decide if we really need to have the "maybeForceBuilderInitialization()"
|
|
+ // method.
|
|
+ // TODO(b/249158148): Remove the need for this entirely
|
|
+ bool need_maybe_force_builder_init = false;
|
|
+ for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
+ if (descriptor_->field(i)->message_type() != nullptr &&
|
|
+ !IsRealOneof(descriptor_->field(i)) &&
|
|
+ HasHasbit(descriptor_->field(i))) {
|
|
+ need_maybe_force_builder_init = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ const char* force_builder_init = need_maybe_force_builder_init
|
|
+ ? " maybeForceBuilderInitialization();"
|
|
+ : "";
|
|
+
|
|
printer->Print(
|
|
"// Construct using $classname$.newBuilder()\n"
|
|
"private Builder() {\n"
|
|
- " maybeForceBuilderInitialization();\n"
|
|
+ "$force_builder_init$\n"
|
|
"}\n"
|
|
"\n",
|
|
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
|
|
+ "classname", name_resolver_->GetImmutableClassName(descriptor_),
|
|
+ "force_builder_init", force_builder_init);
|
|
|
|
printer->Print(
|
|
"private Builder(\n"
|
|
" com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n"
|
|
" super(parent);\n"
|
|
- " maybeForceBuilderInitialization();\n"
|
|
+ "$force_builder_init$\n"
|
|
"}\n",
|
|
"classname", name_resolver_->GetImmutableClassName(descriptor_), "ver",
|
|
- GeneratedCodeVersionSuffix());
|
|
+ GeneratedCodeVersionSuffix(), "force_builder_init", force_builder_init);
|
|
|
|
- printer->Print(
|
|
- "private void maybeForceBuilderInitialization() {\n"
|
|
- " if (com.google.protobuf.GeneratedMessage$ver$\n"
|
|
- " .alwaysUseFieldBuilders) {\n",
|
|
- "ver", GeneratedCodeVersionSuffix());
|
|
+ if (need_maybe_force_builder_init) {
|
|
+ printer->Print(
|
|
+ "private void maybeForceBuilderInitialization() {\n"
|
|
+ " if (com.google.protobuf.GeneratedMessage$ver$\n"
|
|
+ " .alwaysUseFieldBuilders) {\n",
|
|
+ "ver", GeneratedCodeVersionSuffix());
|
|
|
|
- printer->Indent();
|
|
- printer->Indent();
|
|
- for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
- if (!IsRealOneof(descriptor_->field(i))) {
|
|
- field_generators_.get(descriptor_->field(i))
|
|
- .GenerateFieldBuilderInitializationCode(printer);
|
|
+ printer->Indent();
|
|
+ printer->Indent();
|
|
+ for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
+ if (!IsRealOneof(descriptor_->field(i))) {
|
|
+ field_generators_.get(descriptor_->field(i))
|
|
+ .GenerateFieldBuilderInitializationCode(printer);
|
|
+ }
|
|
}
|
|
- }
|
|
- printer->Outdent();
|
|
- printer->Outdent();
|
|
+ printer->Outdent();
|
|
+ printer->Outdent();
|
|
|
|
- printer->Print(
|
|
- " }\n"
|
|
- "}\n");
|
|
+ printer->Print(
|
|
+ " }\n"
|
|
+ "}\n");
|
|
+ }
|
|
|
|
printer->Print(
|
|
"@java.lang.Override\n"
|
|
@@ -331,10 +354,8 @@ void MessageBuilderGenerator::GenerateCommonBuilderMethods(
|
|
printer->Indent();
|
|
|
|
for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
- if (!IsRealOneof(descriptor_->field(i))) {
|
|
- field_generators_.get(descriptor_->field(i))
|
|
- .GenerateBuilderClearCode(printer);
|
|
- }
|
|
+ field_generators_.get(descriptor_->field(i))
|
|
+ .GenerateBuilderClearCode(printer);
|
|
}
|
|
|
|
for (auto oneof : oneofs_) {
|
|
@@ -575,7 +596,7 @@ void MessageBuilderGenerator::GenerateCommonBuilderMethods(
|
|
printer->Print(" this.mergeExtensionFields(other);\n");
|
|
}
|
|
|
|
- printer->Print(" this.mergeUnknownFields(other.unknownFields);\n");
|
|
+ printer->Print(" this.mergeUnknownFields(other.getUnknownFields());\n");
|
|
|
|
printer->Print(" onChanged();\n");
|
|
|
|
@@ -596,20 +617,92 @@ void MessageBuilderGenerator::GenerateBuilderParsingMethods(
|
|
" com.google.protobuf.CodedInputStream input,\n"
|
|
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
|
|
" throws java.io.IOException {\n"
|
|
- " $classname$ parsedMessage = null;\n"
|
|
+ " if (extensionRegistry == null) {\n"
|
|
+ " throw new java.lang.NullPointerException();\n"
|
|
+ " }\n"
|
|
" try {\n"
|
|
- " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
|
|
+ " boolean done = false;\n"
|
|
+ " while (!done) {\n"
|
|
+ " int tag = input.readTag();\n"
|
|
+ " switch (tag) {\n"
|
|
+ " case 0:\n" // zero signals EOF / limit reached
|
|
+ " done = true;\n"
|
|
+ " break;\n");
|
|
+ printer->Indent(); // method
|
|
+ printer->Indent(); // try
|
|
+ printer->Indent(); // while
|
|
+ printer->Indent(); // switch
|
|
+ GenerateBuilderFieldParsingCases(printer);
|
|
+ printer->Outdent(); // switch
|
|
+ printer->Outdent(); // while
|
|
+ printer->Outdent(); // try
|
|
+ printer->Outdent(); // method
|
|
+ printer->Print(
|
|
+ " default: {\n"
|
|
+ " if (!super.parseUnknownField(input, extensionRegistry, tag)) "
|
|
+ "{\n"
|
|
+ " done = true; // was an endgroup tag\n"
|
|
+ " }\n"
|
|
+ " break;\n"
|
|
+ " } // default:\n"
|
|
+ " } // switch (tag)\n"
|
|
+ " } // while (!done)\n"
|
|
" } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
|
|
- " parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
|
|
" throw e.unwrapIOException();\n"
|
|
" } finally {\n"
|
|
- " if (parsedMessage != null) {\n"
|
|
- " mergeFrom(parsedMessage);\n"
|
|
- " }\n"
|
|
- " }\n"
|
|
+ " onChanged();\n"
|
|
+ " } // finally\n"
|
|
" return this;\n"
|
|
- "}\n",
|
|
- "classname", name_resolver_->GetImmutableClassName(descriptor_));
|
|
+ "}\n");
|
|
+}
|
|
+
|
|
+void MessageBuilderGenerator::GenerateBuilderFieldParsingCases(
|
|
+ io::Printer* printer) {
|
|
+ std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
|
|
+ SortFieldsByNumber(descriptor_));
|
|
+ for (int i = 0; i < descriptor_->field_count(); i++) {
|
|
+ const FieldDescriptor* field = sorted_fields[i];
|
|
+ GenerateBuilderFieldParsingCase(printer, field);
|
|
+ if (field->is_packable()) {
|
|
+ GenerateBuilderPackedFieldParsingCase(printer, field);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void MessageBuilderGenerator::GenerateBuilderFieldParsingCase(
|
|
+ io::Printer* printer, const FieldDescriptor* field) {
|
|
+ uint32_t tag = WireFormatLite::MakeTag(
|
|
+ field->number(), WireFormat::WireTypeForFieldType(field->type()));
|
|
+ std::string tagString = StrCat(static_cast<int32_t>(tag));
|
|
+ printer->Print("case $tag$: {\n", "tag", tagString);
|
|
+ printer->Indent();
|
|
+
|
|
+ field_generators_.get(field).GenerateBuilderParsingCode(printer);
|
|
+
|
|
+ printer->Outdent();
|
|
+ printer->Print(
|
|
+ " break;\n"
|
|
+ "} // case $tag$\n",
|
|
+ "tag", tagString);
|
|
+}
|
|
+
|
|
+void MessageBuilderGenerator::GenerateBuilderPackedFieldParsingCase(
|
|
+ io::Printer* printer, const FieldDescriptor* field) {
|
|
+ // To make packed = true wire compatible, we generate parsing code from a
|
|
+ // packed version of this field regardless of field->options().packed().
|
|
+ uint32_t tag = WireFormatLite::MakeTag(
|
|
+ field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
|
+ std::string tagString = StrCat(static_cast<int32_t>(tag));
|
|
+ printer->Print("case $tag$: {\n", "tag", tagString);
|
|
+ printer->Indent();
|
|
+
|
|
+ field_generators_.get(field).GenerateBuilderParsingCodeFromPacked(printer);
|
|
+
|
|
+ printer->Outdent();
|
|
+ printer->Print(
|
|
+ " break;\n"
|
|
+ "} // case $tag$\n",
|
|
+ "tag", tagString);
|
|
}
|
|
|
|
// ===================================================================
|
|
diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h
|
|
index fcd73b3..96f289a 100644
|
|
--- a/src/google/protobuf/compiler/java/java_message_builder.h
|
|
+++ b/src/google/protobuf/compiler/java/java_message_builder.h
|
|
@@ -70,6 +70,11 @@ class MessageBuilderGenerator {
|
|
void GenerateCommonBuilderMethods(io::Printer* printer);
|
|
void GenerateDescriptorMethods(io::Printer* printer);
|
|
void GenerateBuilderParsingMethods(io::Printer* printer);
|
|
+ void GenerateBuilderFieldParsingCases(io::Printer* printer);
|
|
+ void GenerateBuilderFieldParsingCase(io::Printer* printer,
|
|
+ const FieldDescriptor* field);
|
|
+ void GenerateBuilderPackedFieldParsingCase(io::Printer* printer,
|
|
+ const FieldDescriptor* field);
|
|
void GenerateIsInitialized(io::Printer* printer);
|
|
|
|
const Descriptor* descriptor_;
|
|
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
|
|
index 96c0c11..a1db832 100644
|
|
--- a/src/google/protobuf/compiler/java/java_message_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
|
|
@@ -102,13 +102,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
|
|
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
|
|
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
|
|
|
|
- // For repeated fields, one bit is used for whether the array is immutable
|
|
- // in the parsing constructor.
|
|
- (*variables)["get_mutable_bit_parser"] =
|
|
- GenerateGetBitMutableLocal(builderBitIndex);
|
|
- (*variables)["set_mutable_bit_parser"] =
|
|
- GenerateSetBitMutableLocal(builderBitIndex);
|
|
-
|
|
(*variables)["get_has_field_bit_from_local"] =
|
|
GenerateGetBitFromLocal(builderBitIndex);
|
|
(*variables)["set_has_field_bit_to_local"] =
|
|
@@ -456,35 +449,21 @@ void ImmutableMessageFieldGenerator::GenerateBuildingCode(
|
|
}
|
|
}
|
|
|
|
-void ImmutableMessageFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
- printer->Print(variables_,
|
|
- "$type$.Builder subBuilder = null;\n"
|
|
- "if ($is_field_present_message$) {\n"
|
|
- " subBuilder = $name$_.toBuilder();\n"
|
|
- "}\n");
|
|
-
|
|
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
|
printer->Print(variables_,
|
|
- "$name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
|
|
- " extensionRegistry);\n");
|
|
+ "input.readGroup($number$,\n"
|
|
+ " get$capitalized_name$FieldBuilder().getBuilder(),\n"
|
|
+ " extensionRegistry);\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
} else {
|
|
printer->Print(variables_,
|
|
- "$name$_ = input.readMessage($type$.$get_parser$, "
|
|
- "extensionRegistry);\n");
|
|
+ "input.readMessage(\n"
|
|
+ " get$capitalized_name$FieldBuilder().getBuilder(),\n"
|
|
+ " extensionRegistry);\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
}
|
|
-
|
|
- printer->Print(variables_,
|
|
- "if (subBuilder != null) {\n"
|
|
- " subBuilder.mergeFrom($name$_);\n"
|
|
- " $name$_ = subBuilder.buildPartial();\n"
|
|
- "}\n"
|
|
- "$set_has_field_bit_message$\n");
|
|
-}
|
|
-
|
|
-void ImmutableMessageFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- // noop for messages.
|
|
}
|
|
|
|
void ImmutableMessageFieldGenerator::GenerateSerializationCode(
|
|
@@ -736,6 +715,15 @@ void ImmutableMessageOneofFieldGenerator::GenerateBuilderMembers(
|
|
printer->Annotate("{", "}", descriptor_);
|
|
}
|
|
|
|
+void ImmutableMessageOneofFieldGenerator::GenerateBuilderClearCode(
|
|
+ io::Printer* printer) const {
|
|
+ // Make sure the builder gets cleared.
|
|
+ printer->Print(variables_,
|
|
+ "if ($name$Builder_ != null) {\n"
|
|
+ " $name$Builder_.clear();\n"
|
|
+ "}\n");
|
|
+}
|
|
+
|
|
void ImmutableMessageOneofFieldGenerator::GenerateBuildingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_, "if ($has_oneof_case_message$) {\n");
|
|
@@ -756,32 +744,21 @@ void ImmutableMessageOneofFieldGenerator::GenerateMergingCode(
|
|
"merge$capitalized_name$(other.get$capitalized_name$());\n");
|
|
}
|
|
|
|
-void ImmutableMessageOneofFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableMessageOneofFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
- printer->Print(variables_,
|
|
- "$type$.Builder subBuilder = null;\n"
|
|
- "if ($has_oneof_case_message$) {\n"
|
|
- " subBuilder = (($type$) $oneof_name$_).toBuilder();\n"
|
|
- "}\n");
|
|
-
|
|
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "$oneof_name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
|
|
- " extensionRegistry);\n");
|
|
+ printer->Print(variables_,
|
|
+ "input.readGroup($number$,\n"
|
|
+ " get$capitalized_name$FieldBuilder().getBuilder(),\n"
|
|
+ " extensionRegistry);\n"
|
|
+ "$set_oneof_case_message$;\n");
|
|
} else {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "$oneof_name$_ =\n"
|
|
- " input.readMessage($type$.$get_parser$, extensionRegistry);\n");
|
|
+ printer->Print(variables_,
|
|
+ "input.readMessage(\n"
|
|
+ " get$capitalized_name$FieldBuilder().getBuilder(),\n"
|
|
+ " extensionRegistry);\n"
|
|
+ "$set_oneof_case_message$;\n");
|
|
}
|
|
-
|
|
- printer->Print(variables_,
|
|
- "if (subBuilder != null) {\n"
|
|
- " subBuilder.mergeFrom(($type$) $oneof_name$_);\n"
|
|
- " $oneof_name$_ = subBuilder.buildPartial();\n"
|
|
- "}\n");
|
|
- printer->Print(variables_, "$set_oneof_case_message$;\n");
|
|
}
|
|
|
|
void ImmutableMessageOneofFieldGenerator::GenerateSerializationCode(
|
|
@@ -1232,10 +1209,12 @@ void RepeatedImmutableMessageFieldGenerator::GenerateInitializationCode(
|
|
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearCode(
|
|
io::Printer* printer) const {
|
|
PrintNestedBuilderCondition(printer,
|
|
- "$name$_ = java.util.Collections.emptyList();\n"
|
|
- "$clear_mutable_bit_builder$;\n",
|
|
+ "$name$_ = java.util.Collections.emptyList();\n",
|
|
|
|
+ "$name$_ = null;\n"
|
|
"$name$Builder_.clear();\n");
|
|
+
|
|
+ printer->Print(variables_, "$clear_mutable_bit_builder$;\n");
|
|
}
|
|
|
|
void RepeatedImmutableMessageFieldGenerator::GenerateMergingCode(
|
|
@@ -1290,34 +1269,25 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuildingCode(
|
|
"result.$name$_ = $name$Builder_.build();\n");
|
|
}
|
|
|
|
-void RepeatedImmutableMessageFieldGenerator::GenerateParsingCode(
|
|
+void RepeatedImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
- printer->Print(variables_,
|
|
- "if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = new java.util.ArrayList<$type$>();\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- "}\n");
|
|
-
|
|
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "$name$_.add(input.readGroup($number$, $type$.$get_parser$,\n"
|
|
- " extensionRegistry));\n");
|
|
+ printer->Print(variables_,
|
|
+ "$type$ m =\n"
|
|
+ " input.readGroup($number$,\n"
|
|
+ " $type$.$get_parser$,\n"
|
|
+ " extensionRegistry);\n");
|
|
} else {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "$name$_.add(\n"
|
|
- " input.readMessage($type$.$get_parser$, extensionRegistry));\n");
|
|
+ printer->Print(variables_,
|
|
+ "$type$ m =\n"
|
|
+ " input.readMessage(\n"
|
|
+ " $type$.$get_parser$,\n"
|
|
+ " extensionRegistry);\n");
|
|
}
|
|
-}
|
|
-
|
|
-void RepeatedImmutableMessageFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "if ($get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
|
|
- "}\n");
|
|
+ PrintNestedBuilderCondition(printer,
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "$name$_.add(m);\n",
|
|
+ "$name$Builder_.addMessage(m);\n");
|
|
}
|
|
|
|
void RepeatedImmutableMessageFieldGenerator::GenerateSerializationCode(
|
|
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
|
|
index 36fa492..07e0256 100644
|
|
--- a/src/google/protobuf/compiler/java/java_message_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_message_field.h
|
|
@@ -65,24 +65,24 @@ class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
|
|
|
|
// implements ImmutableFieldGenerator
|
|
// ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
protected:
|
|
const FieldDescriptor* descriptor_;
|
|
@@ -110,13 +110,14 @@ class ImmutableMessageOneofFieldGenerator
|
|
Context* context);
|
|
~ImmutableMessageOneofFieldGenerator();
|
|
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
|
|
private:
|
|
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldGenerator);
|
|
@@ -130,24 +131,24 @@ class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
|
|
~RepeatedImmutableMessageFieldGenerator();
|
|
|
|
// implements ImmutableFieldGenerator ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
protected:
|
|
const FieldDescriptor* descriptor_;
|
|
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
|
|
index f06e8fb..b562a2a 100644
|
|
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
|
|
@@ -166,13 +166,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
|
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
|
|
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
|
|
|
|
- // For repeated fields, one bit is used for whether the array is immutable
|
|
- // in the parsing constructor.
|
|
- (*variables)["get_mutable_bit_parser"] =
|
|
- GenerateGetBitMutableLocal(builderBitIndex);
|
|
- (*variables)["set_mutable_bit_parser"] =
|
|
- GenerateSetBitMutableLocal(builderBitIndex);
|
|
-
|
|
(*variables)["get_has_field_bit_from_local"] =
|
|
GenerateGetBitFromLocal(builderBitIndex);
|
|
(*variables)["set_has_field_bit_to_local"] =
|
|
@@ -352,16 +345,11 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
|
|
}
|
|
}
|
|
|
|
-void ImmutablePrimitiveFieldGenerator::GenerateParsingCode(
|
|
+void ImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
- "$set_has_field_bit_message$\n"
|
|
- "$name$_ = input.read$capitalized_type$();\n");
|
|
-}
|
|
-
|
|
-void ImmutablePrimitiveFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- // noop for primitives.
|
|
+ "$name$_ = input.read$capitalized_type$();\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
}
|
|
|
|
void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
|
|
@@ -570,6 +558,12 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
|
printer->Annotate("{", "}", descriptor_);
|
|
}
|
|
|
|
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearCode(
|
|
+ io::Printer* printer) const {
|
|
+ // No-Op: When a primitive field is in a oneof, clearing the oneof clears that
|
|
+ // field.
|
|
+}
|
|
+
|
|
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuildingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
@@ -584,7 +578,7 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateMergingCode(
|
|
"set$capitalized_name$(other.get$capitalized_name$());\n");
|
|
}
|
|
|
|
-void ImmutablePrimitiveOneofFieldGenerator::GenerateParsingCode(
|
|
+void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
"$set_oneof_case_message$;\n"
|
|
@@ -844,38 +838,24 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
|
|
"result.$name$_ = $name$_;\n");
|
|
}
|
|
|
|
-void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingCode(
|
|
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
- "if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = $create_list$;\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- "}\n"
|
|
- "$repeated_add$(input.read$capitalized_type$());\n");
|
|
+ "$type$ v = input.read$capitalized_type$();\n"
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "$repeated_add$(v);\n");
|
|
}
|
|
|
|
-void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingCodeFromPacked(
|
|
- io::Printer* printer) const {
|
|
- printer->Print(
|
|
- variables_,
|
|
- "int length = input.readRawVarint32();\n"
|
|
- "int limit = input.pushLimit(length);\n"
|
|
- "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
|
|
- " $name$_ = $create_list$;\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- "}\n"
|
|
- "while (input.getBytesUntilLimit() > 0) {\n"
|
|
- " $repeated_add$(input.read$capitalized_type$());\n"
|
|
- "}\n"
|
|
- "input.popLimit(limit);\n");
|
|
-}
|
|
-
|
|
-void RepeatedImmutablePrimitiveFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
+void RepeatedImmutablePrimitiveFieldGenerator::
|
|
+ GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
- "if ($get_mutable_bit_parser$) {\n"
|
|
- " $name_make_immutable$; // C\n"
|
|
- "}\n");
|
|
+ "int length = input.readRawVarint32();\n"
|
|
+ "int limit = input.pushLimit(length);\n"
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "while (input.getBytesUntilLimit() > 0) {\n"
|
|
+ " $repeated_add$(input.read$capitalized_type$());\n"
|
|
+ "}\n"
|
|
+ "input.popLimit(limit);\n");
|
|
}
|
|
|
|
void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
|
|
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
|
|
index db20750..e74044a 100644
|
|
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
|
|
@@ -65,24 +65,24 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
|
|
|
|
// implements ImmutableFieldGenerator
|
|
// ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
protected:
|
|
const FieldDescriptor* descriptor_;
|
|
@@ -101,13 +101,14 @@ class ImmutablePrimitiveOneofFieldGenerator
|
|
int builderBitIndex, Context* context);
|
|
~ImmutablePrimitiveOneofFieldGenerator();
|
|
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
|
|
private:
|
|
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldGenerator);
|
|
@@ -122,25 +123,26 @@ class RepeatedImmutablePrimitiveFieldGenerator
|
|
virtual ~RepeatedImmutablePrimitiveFieldGenerator();
|
|
|
|
// implements ImmutableFieldGenerator ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCodeFromPacked(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCodeFromPacked(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
private:
|
|
const FieldDescriptor* descriptor_;
|
|
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
|
|
index 548f898..6edac5e 100644
|
|
--- a/src/google/protobuf/compiler/java/java_string_field.cc
|
|
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
|
|
@@ -118,13 +118,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
|
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
|
|
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
|
|
|
|
- // For repeated fields, one bit is used for whether the array is immutable
|
|
- // in the parsing constructor.
|
|
- (*variables)["get_mutable_bit_parser"] =
|
|
- GenerateGetBitMutableLocal(builderBitIndex);
|
|
- (*variables)["set_mutable_bit_parser"] =
|
|
- GenerateSetBitMutableLocal(builderBitIndex);
|
|
-
|
|
(*variables)["get_has_field_bit_from_local"] =
|
|
GenerateGetBitFromLocal(builderBitIndex);
|
|
(*variables)["set_has_field_bit_to_local"] =
|
|
@@ -413,26 +406,19 @@ void ImmutableStringFieldGenerator::GenerateBuildingCode(
|
|
printer->Print(variables_, "result.$name$_ = $name$_;\n");
|
|
}
|
|
|
|
-void ImmutableStringFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableStringFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
if (CheckUtf8(descriptor_)) {
|
|
printer->Print(variables_,
|
|
- "java.lang.String s = input.readStringRequireUtf8();\n"
|
|
- "$set_has_field_bit_message$\n"
|
|
- "$name$_ = s;\n");
|
|
+ "$name$_ = input.readStringRequireUtf8();\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
} else {
|
|
printer->Print(variables_,
|
|
- "com.google.protobuf.ByteString bs = input.readBytes();\n"
|
|
- "$set_has_field_bit_message$\n"
|
|
- "$name$_ = bs;\n");
|
|
+ "$name$_ = input.readBytes();\n"
|
|
+ "$set_has_field_bit_builder$\n");
|
|
}
|
|
}
|
|
|
|
-void ImmutableStringFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- // noop for strings.
|
|
-}
|
|
-
|
|
void ImmutableStringFieldGenerator::GenerateSerializationCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
@@ -661,6 +647,11 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|
"}\n");
|
|
}
|
|
|
|
+void ImmutableStringOneofFieldGenerator::GenerateBuilderClearCode(
|
|
+ io::Printer* printer) const {
|
|
+ // No-Op: String fields in oneofs are correctly cleared by clearing the oneof
|
|
+}
|
|
+
|
|
void ImmutableStringOneofFieldGenerator::GenerateMergingCode(
|
|
io::Printer* printer) const {
|
|
// Allow a slight breach of abstraction here in order to avoid forcing
|
|
@@ -679,7 +670,7 @@ void ImmutableStringOneofFieldGenerator::GenerateBuildingCode(
|
|
"}\n");
|
|
}
|
|
|
|
-void ImmutableStringOneofFieldGenerator::GenerateParsingCode(
|
|
+void ImmutableStringOneofFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
if (CheckUtf8(descriptor_)) {
|
|
printer->Print(variables_,
|
|
@@ -969,35 +960,21 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuildingCode(
|
|
"result.$name$_ = $name$_;\n");
|
|
}
|
|
|
|
-void RepeatedImmutableStringFieldGenerator::GenerateParsingCode(
|
|
+void RepeatedImmutableStringFieldGenerator::GenerateBuilderParsingCode(
|
|
io::Printer* printer) const {
|
|
if (CheckUtf8(descriptor_)) {
|
|
printer->Print(variables_,
|
|
- "java.lang.String s = input.readStringRequireUtf8();\n");
|
|
+ "java.lang.String s = input.readStringRequireUtf8();\n"
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "$name$_.add(s);\n");
|
|
} else {
|
|
printer->Print(variables_,
|
|
- "com.google.protobuf.ByteString bs = input.readBytes();\n");
|
|
- }
|
|
- printer->Print(variables_,
|
|
- "if (!$get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
|
|
- " $set_mutable_bit_parser$;\n"
|
|
- "}\n");
|
|
- if (CheckUtf8(descriptor_)) {
|
|
- printer->Print(variables_, "$name$_.add(s);\n");
|
|
- } else {
|
|
- printer->Print(variables_, "$name$_.add(bs);\n");
|
|
+ "com.google.protobuf.ByteString bs = input.readBytes();\n"
|
|
+ "ensure$capitalized_name$IsMutable();\n"
|
|
+ "$name$_.add(bs);\n");
|
|
}
|
|
}
|
|
|
|
-void RepeatedImmutableStringFieldGenerator::GenerateParsingDoneCode(
|
|
- io::Printer* printer) const {
|
|
- printer->Print(variables_,
|
|
- "if ($get_mutable_bit_parser$) {\n"
|
|
- " $name$_ = $name$_.getUnmodifiableView();\n"
|
|
- "}\n");
|
|
-}
|
|
-
|
|
void RepeatedImmutableStringFieldGenerator::GenerateSerializationCode(
|
|
io::Printer* printer) const {
|
|
printer->Print(variables_,
|
|
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
|
|
index 1c00ae8..4aaabfb 100644
|
|
--- a/src/google/protobuf/compiler/java/java_string_field.h
|
|
+++ b/src/google/protobuf/compiler/java/java_string_field.h
|
|
@@ -65,24 +65,24 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
|
|
|
|
// implements ImmutableFieldGenerator
|
|
// ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
protected:
|
|
const FieldDescriptor* descriptor_;
|
|
@@ -102,13 +102,14 @@ class ImmutableStringOneofFieldGenerator
|
|
~ImmutableStringOneofFieldGenerator();
|
|
|
|
private:
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
|
|
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldGenerator);
|
|
};
|
|
@@ -121,24 +122,24 @@ class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
|
|
~RepeatedImmutableStringFieldGenerator();
|
|
|
|
// implements ImmutableFieldGenerator ---------------------------------------
|
|
- int GetNumBitsForMessage() const;
|
|
- int GetNumBitsForBuilder() const;
|
|
- void GenerateInterfaceMembers(io::Printer* printer) const;
|
|
- void GenerateMembers(io::Printer* printer) const;
|
|
- void GenerateBuilderMembers(io::Printer* printer) const;
|
|
- void GenerateInitializationCode(io::Printer* printer) const;
|
|
- void GenerateBuilderClearCode(io::Printer* printer) const;
|
|
- void GenerateMergingCode(io::Printer* printer) const;
|
|
- void GenerateBuildingCode(io::Printer* printer) const;
|
|
- void GenerateParsingCode(io::Printer* printer) const;
|
|
- void GenerateParsingDoneCode(io::Printer* printer) const;
|
|
- void GenerateSerializationCode(io::Printer* printer) const;
|
|
- void GenerateSerializedSizeCode(io::Printer* printer) const;
|
|
- void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
|
|
- void GenerateEqualsCode(io::Printer* printer) const;
|
|
- void GenerateHashCode(io::Printer* printer) const;
|
|
-
|
|
- std::string GetBoxedType() const;
|
|
+ int GetNumBitsForMessage() const override;
|
|
+ int GetNumBitsForBuilder() const override;
|
|
+ void GenerateInterfaceMembers(io::Printer* printer) const override;
|
|
+ void GenerateMembers(io::Printer* printer) const override;
|
|
+ void GenerateBuilderMembers(io::Printer* printer) const override;
|
|
+ void GenerateInitializationCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderClearCode(io::Printer* printer) const override;
|
|
+ void GenerateMergingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuildingCode(io::Printer* printer) const override;
|
|
+ void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializationCode(io::Printer* printer) const override;
|
|
+ void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
|
+ void GenerateFieldBuilderInitializationCode(
|
|
+ io::Printer* printer) const override;
|
|
+ void GenerateEqualsCode(io::Printer* printer) const override;
|
|
+ void GenerateHashCode(io::Printer* printer) const override;
|
|
+
|
|
+ std::string GetBoxedType() const override;
|
|
|
|
private:
|
|
const FieldDescriptor* descriptor_;
|
|
--
|
|
2.25.1
|
|
|