diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java index fe532dca0cc21..1e4019a848767 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -1028,7 +1028,23 @@ public boolean isInitialized() { * numbers, but we must write them in canonical (sorted by field number) order. ExtensionWriter * helps us write individual ranges of extensions at once. */ - protected class ExtensionWriter { + protected interface ExtensionWriter { + public void writeUntil(final int end, final CodedOutputStream output) throws IOException; + } + + // Singleton instance so we can avoid allocating a new one for each message serialization. + private static final NoOpExtensionWriter NO_OP_EXTENSION_WRITER = new NoOpExtensionWriter(); + + /** No-op implementation that writes nothing, for messages with no extensions. */ + private static final class NoOpExtensionWriter implements ExtensionWriter { + @Override + public void writeUntil(final int end, final CodedOutputStream output) { + // no-op + } + } + + /** Implementation that writes extensions from the FieldSet, for messages with extensions. */ + private final class FieldSetExtensionWriter implements ExtensionWriter { // Imagine how much simpler this code would be if Java iterators had // a way to get the next element without advancing the iterator. @@ -1036,13 +1052,14 @@ protected class ExtensionWriter { private Map.Entry next; private final boolean messageSetWireFormat; - private ExtensionWriter(final boolean messageSetWireFormat) { + private FieldSetExtensionWriter(final boolean messageSetWireFormat) { if (iter.hasNext()) { next = iter.next(); } this.messageSetWireFormat = messageSetWireFormat; } + @Override public void writeUntil(final int end, final CodedOutputStream output) throws IOException { while (next != null && next.getKey().getNumber() < end) { FieldDescriptor descriptor = next.getKey(); @@ -1076,11 +1093,19 @@ public void writeUntil(final int end, final CodedOutputStream output) throws IOE } protected ExtensionWriter newExtensionWriter() { - return new ExtensionWriter(false); + // Avoid allocation in the common case of no extensions. + if (extensions.isEmpty()) { + return NO_OP_EXTENSION_WRITER; + } + return new FieldSetExtensionWriter(false); } protected ExtensionWriter newMessageSetExtensionWriter() { - return new ExtensionWriter(true); + // Avoid allocation in the common case of no extensions. + if (extensions.isEmpty()) { + return NO_OP_EXTENSION_WRITER; + } + return new FieldSetExtensionWriter(true); } /** Called by subclasses to compute the size of extensions. */ diff --git a/src/google/protobuf/compiler/java/full/message.cc b/src/google/protobuf/compiler/java/full/message.cc index 10abbb90e876f..3456a98b763d4 100644 --- a/src/google/protobuf/compiler/java/full/message.cc +++ b/src/google/protobuf/compiler/java/full/message.cc @@ -587,15 +587,13 @@ void ImmutableMessageGenerator::GenerateMessageSerializationMethods( if (descriptor_->options().message_set_wire_format()) { printer->Print( "com.google.protobuf.GeneratedMessage\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newMessageSetExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + " .ExtendableMessage.ExtensionWriter\n" + " extensionWriter = newMessageSetExtensionWriter();\n"); } else { printer->Print( "com.google.protobuf.GeneratedMessage\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + " .ExtendableMessage.ExtensionWriter\n" + " extensionWriter = newExtensionWriter();\n"); } }