diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index 7bb3c9aadf..af7ce87e27 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -602,9 +602,11 @@ final class FieldSet> { && !descriptor.isPacked()) { Object value = entry.getValue(); if (value instanceof LazyField) { - value = ((LazyField) value).getValue(); + ByteString valueBytes = ((LazyField) value).toByteString(); + output.writeRawMessageSetExtension(entry.getKey().getNumber(), valueBytes); + } else { + output.writeMessageSetExtension(entry.getKey().getNumber(), (MessageLite) value); } - output.writeMessageSetExtension(entry.getKey().getNumber(), (MessageLite) value); } else { writeField(descriptor, entry.getValue(), output); } diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java index abe7cafa79..3afdc1b4d2 100644 --- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -38,12 +38,14 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; import dynamicmessagetest.DynamicMessageTestProto.EmptyMessage; import dynamicmessagetest.DynamicMessageTestProto.MessageWithMapFields; +import protobuf_unittest.UnittestMset.TestMessageSetExtension2; import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestPackedTypes; +import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; import java.util.ArrayList; import org.junit.Test; import org.junit.function.ThrowingRunnable; @@ -401,4 +403,40 @@ public class DynamicMessageTest { } }); } + + @Test + public void serialize_lazyFieldInMessageSet() throws Exception { + ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); + extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); + TestMessageSetExtension2 messageSetExtension = + TestMessageSetExtension2.newBuilder().setStr("foo").build(); + // This is a valid serialization of the above message. + ByteString suboptimallySerializedMessageSetExtension = + messageSetExtension.toByteString().concat(messageSetExtension.toByteString()); + DynamicMessage expectedMessage = + DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) + .setField( + TestMessageSetExtension2.messageSetExtension.getDescriptor(), messageSetExtension) + .build(); + // Constructed with a LazyField, for whom roundtripping the serialized form will shorten the + // encoded form. + // In particular, this checks matching between lazy field encoding size. + DynamicMessage complicatedlyBuiltMessage = + DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) + .setField( + TestMessageSetExtension2.messageSetExtension.getDescriptor(), + new LazyField( + DynamicMessage.getDefaultInstance(TestMessageSetExtension2.getDescriptor()), + extensionRegistry, + suboptimallySerializedMessageSetExtension)) + .build(); + + DynamicMessage roundtrippedMessage = + DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) + .mergeFrom(complicatedlyBuiltMessage.toByteString(), extensionRegistry) + .build(); + + assertThat(complicatedlyBuiltMessage).isEqualTo(expectedMessage); + assertThat(roundtrippedMessage).isEqualTo(expectedMessage); + } }