Refactoring Java parsing (21.x) (#10665)

* Porting java cleanup

* Update changelog

* Fix absl usage

* Extension patch

* Remove extra allocations
pull/10673/head
Mike Kruskal 2 years ago committed by GitHub
parent bea6726c73
commit 3b5301c114
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      CHANGES.txt
  2. 27
      java/core/src/main/java/com/google/protobuf/AbstractMessage.java
  3. 146
      java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
  4. 32
      java/core/src/main/java/com/google/protobuf/BinaryReader.java
  5. 51
      java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
  6. 4
      java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
  7. 5
      java/core/src/main/java/com/google/protobuf/DynamicMessage.java
  8. 1
      java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
  9. 5
      java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
  10. 52
      java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
  11. 63
      java/core/src/main/java/com/google/protobuf/FieldSet.java
  12. 167
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  13. 110
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  14. 117
      java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
  15. 391
      java/core/src/main/java/com/google/protobuf/MessageReflection.java
  16. 485
      java/core/src/main/java/com/google/protobuf/MessageSchema.java
  17. 17
      java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
  18. 5
      java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
  19. 8
      java/core/src/main/java/com/google/protobuf/Reader.java
  20. 32
      java/core/src/main/java/com/google/protobuf/SchemaUtil.java
  21. 2
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  22. 39
      java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
  23. 12
      java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
  24. 21
      java/lite/src/test/java/com/google/protobuf/LiteTest.java
  25. 7
      java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
  26. 94
      src/google/protobuf/compiler/java/enum_field.cc
  27. 12
      src/google/protobuf/compiler/java/enum_field.h
  28. 4
      src/google/protobuf/compiler/java/field.cc
  29. 5
      src/google/protobuf/compiler/java/field.h
  30. 30
      src/google/protobuf/compiler/java/map_field.cc
  31. 3
      src/google/protobuf/compiler/java/map_field.h
  32. 223
      src/google/protobuf/compiler/java/message.cc
  33. 163
      src/google/protobuf/compiler/java/message_builder.cc
  34. 5
      src/google/protobuf/compiler/java/message_builder.h
  35. 126
      src/google/protobuf/compiler/java/message_field.cc
  36. 9
      src/google/protobuf/compiler/java/message_field.h
  37. 66
      src/google/protobuf/compiler/java/primitive_field.cc
  38. 12
      src/google/protobuf/compiler/java/primitive_field.h
  39. 59
      src/google/protobuf/compiler/java/string_field.cc
  40. 9
      src/google/protobuf/compiler/java/string_field.h

@ -1,3 +1,14 @@
2022-09-27 version 21.7 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
Java
* Refactoring java full runtime to reuse sub-message builders and prepare to
migrate parsing logic from parse constructor to builder.
* Move proto wireformat parsing functionality from the private "parsing
constructor" to the Builder class.
* Change the Lite runtime to prefer merging from the wireformat into mutable
messages rather than building up a new immutable object before merging. This
way results in fewer allocations and copy operations.
* Make message-type extensions merge from wire-format instead of building up instances and merging afterwards. This has much better performance.
2022-09-13 version 21.6 (C++/Java/Python/PHP/Objective-C/C#/Ruby)
C++

@ -424,27 +424,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(

@ -237,6 +237,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);
@ -245,27 +268,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;
}
@ -851,26 +875,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());
@ -882,13 +899,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.
@ -945,20 +957,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.");
}
@ -966,17 +1003,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);
}
}

@ -248,6 +248,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);
@ -257,15 +266,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;
@ -290,19 +294,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;

@ -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);

@ -427,8 +427,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;
}

@ -413,7 +413,10 @@ public final class DynamicMessage extends AbstractMessage {
DynamicMessage result =
new DynamicMessage(
type, fields.build(), Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
type,
fields.buildPartial(),
Arrays.copyOf(oneofCases, oneofCases.length),
unknownFields);
return result;
}

@ -60,6 +60,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,

@ -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 {

@ -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;
@ -68,6 +67,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
@Override
<UT, UB> UB parseExtension(
Object containerMessage,
Reader reader,
Object extensionObject,
ExtensionRegistryLite extensionRegistry,
@ -179,6 +179,7 @@ final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
reader.readEnumList(list);
unknownFields =
SchemaUtil.filterUnknownEnumList(
containerMessage,
fieldNumber,
list,
extension.descriptor.getEnumType(),
@ -200,7 +201,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.
@ -254,12 +255,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);
@ -275,6 +310,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);
@ -528,15 +564,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);
}
}

@ -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
@ -123,6 +124,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;
}
@ -926,8 +933,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();
}
@ -936,7 +962,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;
@ -944,22 +970,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;
}
@ -974,7 +1000,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
@ -988,14 +1014,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}. */
@ -1014,7 +1047,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
if (fields.isImmutable()) {
result.makeImmutable();
} else {
replaceBuilders(result);
replaceBuilders(result, true);
}
return result;
}
@ -1037,7 +1070,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. */
@ -1123,7 +1156,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
ensureIsMutable();
}
Object value = getRepeatedFieldAllowBuilders(descriptor, index);
return replaceBuilder(value);
return replaceBuilder(value, true);
}
/**

@ -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);
}
/**
@ -257,14 +308,22 @@ 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
@ -274,12 +333,42 @@ public abstract class GeneratedMessageLite<
.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);
}
private int computeSerializedSize(Schema<?> nullableSchema) {
if (nullableSchema == null) {
return Protobuf.getInstance().schemaFor(this).getSerializedSize(this);
} else {
return ((Schema<GeneratedMessageLite<MessageType, BuilderType>>) nullableSchema)
.getSerializedSize(this);
}
return memoizedSerializedSize;
}
/** Constructs a {@link MessageInfo} for this message type. */
@ -319,6 +408,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(
@ -343,13 +433,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();
}
/**
@ -357,15 +453,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;
}
@ -377,27 +471,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;
}
@ -417,12 +512,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);
}
@ -936,7 +1034,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() {
@ -950,7 +1050,7 @@ public abstract class GeneratedMessageLite<
@Override
public final MessageType buildPartial() {
if (isBuilt) {
if (!instance.isMutable()) {
return instance;
}
@ -1534,7 +1634,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.
@ -1567,15 +1667,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 (InvalidProtocolBufferException e) {
if (e.getThrownFromInputStream()) {
e = new InvalidProtocolBufferException(e);

@ -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(

@ -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, ' ');
}
private MessageLiteToString() {
// Classes which are not intended to be instantiated should be made non-instantiable with a
@ -76,37 +84,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<>();
Map<String, Method> nameToMethod = new HashMap<>();
Set<String> getters = new TreeSet<>();
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;
}
@ -114,12 +136,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
@ -130,29 +149,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);
@ -162,7 +177,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;
}
@ -218,10 +233,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) {
@ -238,10 +253,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('"');
@ -251,9 +264,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(" {");
@ -261,19 +272,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);
}
}
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("_");
}

@ -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);
@ -499,6 +528,60 @@ 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)) {
input.readGroup(field.getNumber(), builder.getFieldBuilder(field), extensionRegistry);
return;
}
Message.Builder 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()) {
if (hasField(field)) {
input.readMessage(builder.getFieldBuilder(field), extensionRegistry);
return;
}
Message.Builder 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) {
@ -665,6 +748,54 @@ 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,
@ -700,7 +831,234 @@ 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;
}
@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
@CanIgnoreReturnValue
public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
extensions.setField(field, value);
return this;
}
@Override
@CanIgnoreReturnValue
public MergeTarget clearField(Descriptors.FieldDescriptor field) {
extensions.clearField(field);
return this;
}
@Override
@CanIgnoreReturnValue
public MergeTarget setRepeatedField(
Descriptors.FieldDescriptor field, int index, Object value) {
extensions.setRepeatedField(field, index, value);
return this;
}
@Override
@CanIgnoreReturnValue
public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
extensions.addRepeatedField(field, value);
return this;
}
@Override
public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
return false;
}
@Override
@CanIgnoreReturnValue
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,
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;
}
@ -829,13 +1187,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 +1228,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,

@ -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;
@ -1177,6 +1178,7 @@ final class MessageSchema<T> implements Schema<T> {
@Override
public void mergeFrom(T message, T other) {
checkMutable(message);
if (other == null) {
throw new NullPointerException();
}
@ -1375,47 +1377,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:
@ -4879,6 +4872,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;
@ -4995,18 +4989,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;
}
@ -5055,20 +5042,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;
}
@ -5166,7 +5151,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)
@ -5184,10 +5170,66 @@ 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. */
@CanIgnoreReturnValue
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;
@ -5309,16 +5351,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;
}
@ -5449,18 +5486,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) {
@ -5497,8 +5589,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);
@ -5513,25 +5609,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());
@ -5748,6 +5851,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);
}

@ -62,7 +62,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
@ -133,6 +139,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();
@ -181,9 +189,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;

@ -34,7 +34,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();
}
}

@ -159,6 +159,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.

@ -60,6 +60,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)) {
@ -809,6 +811,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,7 +905,9 @@ final class SchemaUtil {
}
/** Filters unrecognized enum values in a list. */
@CanIgnoreReturnValue
static <UT, UB> UB filterUnknownEnumList(
Object containerMessage,
int number,
List<Integer> enumList,
EnumLiteMap<?> enumMap,
@ -922,7 +928,9 @@ final class SchemaUtil {
}
++writePos;
} else {
unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
unknownFields =
storeUnknownEnum(
containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
}
}
if (writePos != size) {
@ -932,7 +940,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,7 +951,9 @@ final class SchemaUtil {
}
/** Filters unrecognized enum values in a list. */
@CanIgnoreReturnValue
static <UT, UB> UB filterUnknownEnumList(
Object containerMessage,
int number,
List<Integer> enumList,
EnumVerifier enumVerifier,
@ -962,7 +974,9 @@ final class SchemaUtil {
}
++writePos;
} else {
unknownFields = storeUnknownEnum(number, enumValue, unknownFields, unknownFieldSchema);
unknownFields =
storeUnknownEnum(
containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
}
}
if (writePos != size) {
@ -972,7 +986,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();
}
}
@ -983,9 +999,13 @@ final class SchemaUtil {
/** Stores an unrecognized enum value as an unknown value. */
@CanIgnoreReturnValue
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;

@ -607,7 +607,7 @@ public final class TextFormat {
case MESSAGE:
case GROUP:
print((Message) value, generator);
print((MessageOrBuilder) value, generator);
break;
}
}

@ -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,19 @@ public final class UnknownFieldSetLite {
}
return this;
}
@CanIgnoreReturnValue
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;
}
}

@ -123,10 +123,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

@ -191,19 +191,28 @@ public class LiteTest {
@Test
public void testMemoization() throws Exception {
TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
GeneratedMessageLite<?, ?> message = TestUtilLite.getAllLiteExtensionsSet();
// This built message should not be mutable
assertThat(message.isMutable()).isFalse();
// Test serialized size is memoized
message.memoizedSerializedSize = -1;
assertThat(message.getMemoizedSerializedSize())
.isEqualTo(GeneratedMessageLite.UNINITIALIZED_SERIALIZED_SIZE);
int size = message.getSerializedSize();
assertThat(size).isGreaterThan(0);
assertThat(message.memoizedSerializedSize).isEqualTo(size);
assertThat(message.getMemoizedSerializedSize()).isEqualTo(size);
message.clearMemoizedSerializedSize();
assertThat(message.getMemoizedSerializedSize())
.isEqualTo(GeneratedMessageLite.UNINITIALIZED_SERIALIZED_SIZE);
// Test hashCode is memoized
assertThat(message.memoizedHashCode).isEqualTo(0);
assertThat(message.hashCodeIsNotMemoized()).isTrue();
int hashCode = message.hashCode();
assertThat(hashCode).isNotEqualTo(0);
assertThat(hashCode).isEqualTo(message.memoizedHashCode);
assertThat(message.hashCodeIsNotMemoized()).isFalse();
assertThat(message.getMemoizedHashCode()).isEqualTo(hashCode);
message.clearMemoizedHashCode();
assertThat(message.hashCodeIsNotMemoized()).isTrue();
// Test isInitialized is memoized
Field memo = message.getClass().getDeclaredField("memoizedIsInitialized");

@ -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;
@ -292,7 +293,11 @@ final class FieldMaskTree {
// so we don't create unnecessary empty messages.
continue;
}
Message.Builder childBuilder = ((Message) destination.getField(field)).toBuilder();
// 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(), (Message) source.getField(field), childBuilder, options);
destination.setField(field, childBuilder.buildPartial());
continue;

@ -121,13 +121,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"] =
@ -354,32 +347,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_,
@ -540,6 +527,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_,
@ -560,7 +552,7 @@ void ImmutableEnumOneofFieldGenerator::GenerateMergingCode(
}
}
void ImmutableEnumOneofFieldGenerator::GenerateParsingCode(
void ImmutableEnumOneofFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
if (SupportUnknownEnumValue(descriptor_->file())) {
printer->Print(variables_,
@ -570,10 +562,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"
@ -952,36 +944,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.
@ -991,7 +976,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateParsingCodeFromPacked(
"while(input.getBytesUntilLimit() > 0) {\n");
printer->Indent();
GenerateParsingCode(printer);
GenerateBuilderParsingCode(printer);
printer->Outdent();
printer->Print(variables_,
@ -999,15 +984,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()) {

@ -72,10 +72,9 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
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 GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(io::Printer* printer) const override;
void GenerateSerializationCode(io::Printer* printer) const override;
void GenerateSerializedSizeCode(io::Printer* printer) const override;
void GenerateFieldBuilderInitializationCode(
@ -104,9 +103,10 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
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 GenerateParsingCode(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;
@ -133,9 +133,9 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingCodeFromPacked(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(

@ -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);
}

@ -77,9 +77,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(

@ -171,13 +171,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
: "";
(*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"];
@ -800,27 +793,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 {
@ -829,16 +814,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_,

@ -55,8 +55,7 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(

@ -42,6 +42,7 @@
#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>
@ -379,6 +380,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"
@ -386,10 +388,6 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
" return this.unknownFields;\n"
"}\n");
if (context_->HasGeneratedMethods(descriptor_)) {
GenerateParsingConstructor(printer);
}
GenerateDescriptorMethods(printer);
// Nested types
@ -638,9 +636,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();
@ -669,9 +667,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(
@ -1068,7 +1067,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"
@ -1142,7 +1142,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");
@ -1167,189 +1167,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_t tag = WireFormatLite::MakeTag(
field->number(), WireFormat::WireTypeForFieldType(field->type()));
printer->Print("case $tag$: {\n", "tag",
StrCat(static_cast<int32_t>(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_t packed_tag = WireFormatLite::MakeTag(
field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
printer->Print("case $tag$: {\n", "tag",
StrCat(static_cast<int32_t>(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 (com.google.protobuf.UninitializedMessageException e) {\n"
" throw "
"e.asInvalidProtocolBufferException().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"
@ -1359,6 +1203,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
" return PARSER;\n"
"}\n"
"\n",
"visibility",
ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public"
: "private",
"classname", descriptor_->name());
}

@ -61,6 +61,9 @@ namespace protobuf {
namespace compiler {
namespace java {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
std::string MapValueImmutableClassdName(const Descriptor* descriptor,
ClassNameResolver* name_resolver) {
@ -288,43 +291,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"
@ -334,10 +357,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_) {
@ -578,7 +599,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");
@ -599,20 +620,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);
}
// ===================================================================

@ -71,6 +71,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_;

@ -113,13 +113,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"] =
@ -504,35 +497,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(
@ -785,6 +764,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");
@ -805,32 +793,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(
@ -1281,10 +1258,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(
@ -1339,34 +1318,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(

@ -75,8 +75,7 @@ class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(
@ -116,9 +115,10 @@ class ImmutableMessageOneofFieldGenerator
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 GenerateParsingCode(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;
@ -143,8 +143,7 @@ class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(

@ -186,13 +186,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"] =
@ -400,16 +393,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(
@ -614,6 +602,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_,
@ -628,7 +622,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_,
"$oneof_name$_ = input.read$capitalized_type$();\n"
@ -982,38 +976,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(

@ -75,8 +75,7 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(
@ -106,9 +105,10 @@ class ImmutablePrimitiveOneofFieldGenerator
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 GenerateParsingCode(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;
@ -134,9 +134,9 @@ class RepeatedImmutablePrimitiveFieldGenerator
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingCodeFromPacked(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(

@ -128,13 +128,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"] =
@ -452,26 +445,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_,
@ -695,6 +681,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
@ -713,7 +704,7 @@ void ImmutableStringOneofFieldGenerator::GenerateBuildingCode(
"}\n");
}
void ImmutableStringOneofFieldGenerator::GenerateParsingCode(
void ImmutableStringOneofFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
if (CheckUtf8(descriptor_)) {
printer->Print(variables_,
@ -1104,35 +1095,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_,

@ -75,8 +75,7 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(
@ -107,9 +106,10 @@ class ImmutableStringOneofFieldGenerator
private:
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 GenerateParsingCode(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;
@ -133,8 +133,7 @@ class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
void GenerateBuilderClearCode(io::Printer* printer) const override;
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateBuildingCode(io::Printer* printer) const override;
void GenerateParsingCode(io::Printer* printer) const override;
void GenerateParsingDoneCode(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(

Loading…
Cancel
Save