diff --git a/CHANGES.txt b/CHANGES.txt index cf9c341e8c3b..ba3e277aecde 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,7 +7,11 @@ * 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. + * Make message-type extensions merge from wire-format instead of building up + instances and merging afterwards. This has much better performance. + * Fix TextFormat parser to build up recurring (but supposedly not repeated) + sub-messages directly from text rather than building a new sub-message and + merging the fully formed message into the existing field. 2022-09-13 version 21.6 (C++/Java/Python/PHP/Objective-C/C#/Ruby) diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java index e9bc9f1330e3..294d84177487 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java +++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java @@ -378,6 +378,7 @@ MergeTarget newEmptyTargetForField( static class BuilderAdapter implements MergeTarget { private final Message.Builder builder; + private boolean hasNestedBuilders = true; @Override public Descriptors.Descriptor getDescriptorForType() { @@ -393,6 +394,17 @@ public Object getField(Descriptors.FieldDescriptor field) { return builder.getField(field); } + private Message.Builder getFieldBuilder(Descriptors.FieldDescriptor field) { + if (hasNestedBuilders) { + try { + return builder.getFieldBuilder(field); + } catch (UnsupportedOperationException e) { + hasNestedBuilders = false; + } + } + return null; + } + @Override public boolean hasField(Descriptors.FieldDescriptor field) { return builder.hasField(field); @@ -400,6 +412,12 @@ public boolean hasField(Descriptors.FieldDescriptor field) { @Override public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { + if (!field.isRepeated() && value instanceof MessageLite.Builder) { + if (value != getFieldBuilder(field)) { + builder.setField(field, ((MessageLite.Builder) value).buildPartial()); + } + return this; + } builder.setField(field, value); return this; } @@ -413,12 +431,18 @@ public MergeTarget clearField(Descriptors.FieldDescriptor field) { @Override public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { + if (value instanceof MessageLite.Builder) { + value = ((MessageLite.Builder) value).buildPartial(); + } builder.setRepeatedField(field, index, value); return this; } @Override public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) { + if (value instanceof MessageLite.Builder) { + value = ((MessageLite.Builder) value).buildPartial(); + } builder.addRepeatedField(field, value); return this; } @@ -536,11 +560,19 @@ public void mergeGroup( Message defaultInstance) throws IOException { if (!field.isRepeated()) { + Message.Builder subBuilder; if (hasField(field)) { - input.readGroup(field.getNumber(), builder.getFieldBuilder(field), extensionRegistry); - return; + subBuilder = getFieldBuilder(field); + if (subBuilder != null) { + input.readGroup(field.getNumber(), subBuilder, extensionRegistry); + return; + } else { + subBuilder = newMessageFieldInstance(field, defaultInstance); + subBuilder.mergeFrom((Message) getField(field)); + } + } else { + subBuilder = newMessageFieldInstance(field, defaultInstance); } - Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance); input.readGroup(field.getNumber(), subBuilder, extensionRegistry); Object unused = setField(field, subBuilder.buildPartial()); } else { @@ -558,11 +590,19 @@ public void mergeMessage( Message defaultInstance) throws IOException { if (!field.isRepeated()) { + Message.Builder subBuilder; if (hasField(field)) { - input.readMessage(builder.getFieldBuilder(field), extensionRegistry); - return; + subBuilder = getFieldBuilder(field); + if (subBuilder != null) { + input.readMessage(subBuilder, extensionRegistry); + return; + } else { + subBuilder = newMessageFieldInstance(field, defaultInstance); + subBuilder.mergeFrom((Message) getField(field)); + } + } else { + subBuilder = newMessageFieldInstance(field, defaultInstance); } - Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance); input.readMessage(subBuilder, extensionRegistry); Object unused = setField(field, subBuilder.buildPartial()); } else { @@ -586,11 +626,14 @@ private Message.Builder newMessageFieldInstance( public MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor field, Message defaultInstance) { Message.Builder subBuilder; - if (defaultInstance != null) { - subBuilder = defaultInstance.newBuilderForType(); - } else { - subBuilder = builder.newBuilderForField(field); + if (!field.isRepeated() && hasField(field)) { + subBuilder = getFieldBuilder(field); + if (subBuilder != null) { + return new BuilderAdapter(subBuilder); + } } + + subBuilder = newMessageFieldInstance(field, defaultInstance); if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); if (originalMessage != null) { @@ -626,7 +669,7 @@ public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor d @Override public Object finish() { - return builder.buildPartial(); + return builder; } }