1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 package com.google.protobuf;
33 import java.io.IOException;
34 import java.io.ObjectStreamException;
35 import java.io.Serializable;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.util.Collections;
39 import java.util.Iterator;
40 import java.util.List;
44 * Lite version of {@link GeneratedMessage}.
46 * @author kenton@google.com Kenton Varda
48 public abstract class GeneratedMessageLite extends AbstractMessageLite
49 implements Serializable {
50 private static final long serialVersionUID = 1L;
52 protected GeneratedMessageLite() {
55 protected GeneratedMessageLite(Builder builder) {
58 public Parser<? extends MessageLite> getParserForType() {
59 throw new UnsupportedOperationException(
60 "This is supposed to be overridden by subclasses.");
64 * Called by subclasses to parse an unknown field.
65 * @return {@code true} unless the tag is an end-group tag.
67 protected boolean parseUnknownField(
68 CodedInputStream input,
69 ExtensionRegistryLite extensionRegistry,
70 int tag) throws IOException {
71 return input.skipField(tag);
75 * Used by parsing constructors in generated classes.
77 protected void makeExtensionsImmutable() {
78 // Noop for messages without extensions.
81 @SuppressWarnings("unchecked")
82 public abstract static class Builder<MessageType extends GeneratedMessageLite,
83 BuilderType extends Builder>
84 extends AbstractMessageLite.Builder<BuilderType> {
85 protected Builder() {}
87 //@Override (Java 1.6 override semantics, but we must support 1.5)
88 public BuilderType clear() {
89 return (BuilderType) this;
92 // This is implemented here only to work around an apparent bug in the
93 // Java compiler and/or build system. See bug #1898463. The mere presence
94 // of this dummy clone() implementation makes it go away.
96 public BuilderType clone() {
97 throw new UnsupportedOperationException(
98 "This is supposed to be overridden by subclasses.");
101 /** All subclasses implement this. */
102 public abstract BuilderType mergeFrom(MessageType message);
104 // Defined here for return type covariance.
105 public abstract MessageType getDefaultInstanceForType();
108 * Called by subclasses to parse an unknown field.
109 * @return {@code true} unless the tag is an end-group tag.
111 protected boolean parseUnknownField(
112 CodedInputStream input,
113 ExtensionRegistryLite extensionRegistry,
114 int tag) throws IOException {
115 return input.skipField(tag);
119 // =================================================================
120 // Extensions-related stuff
123 * Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
125 public interface ExtendableMessageOrBuilder<
126 MessageType extends ExtendableMessage> extends MessageLiteOrBuilder {
128 /** Check if a singular extension is present. */
129 <Type> boolean hasExtension(
130 GeneratedExtension<MessageType, Type> extension);
132 /** Get the number of elements in a repeated extension. */
133 <Type> int getExtensionCount(
134 GeneratedExtension<MessageType, List<Type>> extension);
136 /** Get the value of an extension. */
137 <Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
139 /** Get one element of a repeated extension. */
140 <Type> Type getExtension(
141 GeneratedExtension<MessageType, List<Type>> extension,
146 * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
148 public abstract static class ExtendableMessage<
149 MessageType extends ExtendableMessage<MessageType>>
150 extends GeneratedMessageLite
151 implements ExtendableMessageOrBuilder<MessageType> {
153 private final FieldSet<ExtensionDescriptor> extensions;
155 protected ExtendableMessage() {
156 this.extensions = FieldSet.newFieldSet();
159 protected ExtendableMessage(ExtendableBuilder<MessageType, ?> builder) {
160 this.extensions = builder.buildExtensions();
163 private void verifyExtensionContainingType(
164 final GeneratedExtension<MessageType, ?> extension) {
165 if (extension.getContainingTypeDefaultInstance() !=
166 getDefaultInstanceForType()) {
167 // This can only happen if someone uses unchecked operations.
168 throw new IllegalArgumentException(
169 "This extension is for a different message type. Please make " +
170 "sure that you are not suppressing any generics type warnings.");
174 /** Check if a singular extension is present. */
175 //@Override (Java 1.6 override semantics, but we must support 1.5)
176 public final <Type> boolean hasExtension(
177 final GeneratedExtension<MessageType, Type> extension) {
178 verifyExtensionContainingType(extension);
179 return extensions.hasField(extension.descriptor);
182 /** Get the number of elements in a repeated extension. */
183 //@Override (Java 1.6 override semantics, but we must support 1.5)
184 public final <Type> int getExtensionCount(
185 final GeneratedExtension<MessageType, List<Type>> extension) {
186 verifyExtensionContainingType(extension);
187 return extensions.getRepeatedFieldCount(extension.descriptor);
190 /** Get the value of an extension. */
191 //@Override (Java 1.6 override semantics, but we must support 1.5)
192 @SuppressWarnings("unchecked")
193 public final <Type> Type getExtension(
194 final GeneratedExtension<MessageType, Type> extension) {
195 verifyExtensionContainingType(extension);
196 final Object value = extensions.getField(extension.descriptor);
198 return extension.defaultValue;
204 /** Get one element of a repeated extension. */
205 //@Override (Java 1.6 override semantics, but we must support 1.5)
206 @SuppressWarnings("unchecked")
207 public final <Type> Type getExtension(
208 final GeneratedExtension<MessageType, List<Type>> extension,
210 verifyExtensionContainingType(extension);
211 return (Type) extensions.getRepeatedField(extension.descriptor, index);
214 /** Called by subclasses to check if all extensions are initialized. */
215 protected boolean extensionsAreInitialized() {
216 return extensions.isInitialized();
220 * Called by subclasses to parse an unknown field or an extension.
221 * @return {@code true} unless the tag is an end-group tag.
224 protected boolean parseUnknownField(
225 CodedInputStream input,
226 ExtensionRegistryLite extensionRegistry,
227 int tag) throws IOException {
228 return GeneratedMessageLite.parseUnknownField(
230 getDefaultInstanceForType(),
237 * Used by parsing constructors in generated classes.
240 protected void makeExtensionsImmutable() {
241 extensions.makeImmutable();
245 * Used by subclasses to serialize extensions. Extension ranges may be
246 * interleaved with field numbers, but we must write them in canonical
247 * (sorted by field number) order. ExtensionWriter helps us write
248 * individual ranges of extensions at once.
250 protected class ExtensionWriter {
251 // Imagine how much simpler this code would be if Java iterators had
252 // a way to get the next element without advancing the iterator.
254 private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
255 extensions.iterator();
256 private Map.Entry<ExtensionDescriptor, Object> next;
257 private final boolean messageSetWireFormat;
259 private ExtensionWriter(boolean messageSetWireFormat) {
260 if (iter.hasNext()) {
263 this.messageSetWireFormat = messageSetWireFormat;
266 public void writeUntil(final int end, final CodedOutputStream output)
268 while (next != null && next.getKey().getNumber() < end) {
269 ExtensionDescriptor extension = next.getKey();
270 if (messageSetWireFormat && extension.getLiteJavaType() ==
271 WireFormat.JavaType.MESSAGE &&
272 !extension.isRepeated()) {
273 output.writeMessageSetExtension(extension.getNumber(),
274 (MessageLite) next.getValue());
276 FieldSet.writeField(extension, next.getValue(), output);
278 if (iter.hasNext()) {
287 protected ExtensionWriter newExtensionWriter() {
288 return new ExtensionWriter(false);
290 protected ExtensionWriter newMessageSetExtensionWriter() {
291 return new ExtensionWriter(true);
294 /** Called by subclasses to compute the size of extensions. */
295 protected int extensionsSerializedSize() {
296 return extensions.getSerializedSize();
298 protected int extensionsSerializedSizeAsMessageSet() {
299 return extensions.getMessageSetSerializedSize();
304 * Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
306 @SuppressWarnings("unchecked")
307 public abstract static class ExtendableBuilder<
308 MessageType extends ExtendableMessage<MessageType>,
309 BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
310 extends Builder<MessageType, BuilderType>
311 implements ExtendableMessageOrBuilder<MessageType> {
312 protected ExtendableBuilder() {}
314 private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
315 private boolean extensionsIsMutable;
318 public BuilderType clear() {
320 extensionsIsMutable = false;
321 return super.clear();
324 private void ensureExtensionsIsMutable() {
325 if (!extensionsIsMutable) {
326 extensions = extensions.clone();
327 extensionsIsMutable = true;
332 * Called by the build code path to create a copy of the extensions for
333 * building the message.
335 private FieldSet<ExtensionDescriptor> buildExtensions() {
336 extensions.makeImmutable();
337 extensionsIsMutable = false;
341 private void verifyExtensionContainingType(
342 final GeneratedExtension<MessageType, ?> extension) {
343 if (extension.getContainingTypeDefaultInstance() !=
344 getDefaultInstanceForType()) {
345 // This can only happen if someone uses unchecked operations.
346 throw new IllegalArgumentException(
347 "This extension is for a different message type. Please make " +
348 "sure that you are not suppressing any generics type warnings.");
352 /** Check if a singular extension is present. */
353 //@Override (Java 1.6 override semantics, but we must support 1.5)
354 public final <Type> boolean hasExtension(
355 final GeneratedExtension<MessageType, Type> extension) {
356 verifyExtensionContainingType(extension);
357 return extensions.hasField(extension.descriptor);
360 /** Get the number of elements in a repeated extension. */
361 //@Override (Java 1.6 override semantics, but we must support 1.5)
362 public final <Type> int getExtensionCount(
363 final GeneratedExtension<MessageType, List<Type>> extension) {
364 verifyExtensionContainingType(extension);
365 return extensions.getRepeatedFieldCount(extension.descriptor);
368 /** Get the value of an extension. */
369 //@Override (Java 1.6 override semantics, but we must support 1.5)
370 @SuppressWarnings("unchecked")
371 public final <Type> Type getExtension(
372 final GeneratedExtension<MessageType, Type> extension) {
373 verifyExtensionContainingType(extension);
374 final Object value = extensions.getField(extension.descriptor);
376 return extension.defaultValue;
382 /** Get one element of a repeated extension. */
383 @SuppressWarnings("unchecked")
384 //@Override (Java 1.6 override semantics, but we must support 1.5)
385 public final <Type> Type getExtension(
386 final GeneratedExtension<MessageType, List<Type>> extension,
388 verifyExtensionContainingType(extension);
389 return (Type) extensions.getRepeatedField(extension.descriptor, index);
392 // This is implemented here only to work around an apparent bug in the
393 // Java compiler and/or build system. See bug #1898463. The mere presence
394 // of this dummy clone() implementation makes it go away.
396 public BuilderType clone() {
397 throw new UnsupportedOperationException(
398 "This is supposed to be overridden by subclasses.");
401 /** Set the value of an extension. */
402 public final <Type> BuilderType setExtension(
403 final GeneratedExtension<MessageType, Type> extension,
405 verifyExtensionContainingType(extension);
406 ensureExtensionsIsMutable();
407 extensions.setField(extension.descriptor, value);
408 return (BuilderType) this;
411 /** Set the value of one element of a repeated extension. */
412 public final <Type> BuilderType setExtension(
413 final GeneratedExtension<MessageType, List<Type>> extension,
414 final int index, final Type value) {
415 verifyExtensionContainingType(extension);
416 ensureExtensionsIsMutable();
417 extensions.setRepeatedField(extension.descriptor, index, value);
418 return (BuilderType) this;
421 /** Append a value to a repeated extension. */
422 public final <Type> BuilderType addExtension(
423 final GeneratedExtension<MessageType, List<Type>> extension,
425 verifyExtensionContainingType(extension);
426 ensureExtensionsIsMutable();
427 extensions.addRepeatedField(extension.descriptor, value);
428 return (BuilderType) this;
431 /** Clear an extension. */
432 public final <Type> BuilderType clearExtension(
433 final GeneratedExtension<MessageType, ?> extension) {
434 verifyExtensionContainingType(extension);
435 ensureExtensionsIsMutable();
436 extensions.clearField(extension.descriptor);
437 return (BuilderType) this;
440 /** Called by subclasses to check if all extensions are initialized. */
441 protected boolean extensionsAreInitialized() {
442 return extensions.isInitialized();
446 * Called by subclasses to parse an unknown field or an extension.
447 * @return {@code true} unless the tag is an end-group tag.
450 protected boolean parseUnknownField(
451 CodedInputStream input,
452 ExtensionRegistryLite extensionRegistry,
453 int tag) throws IOException {
454 ensureExtensionsIsMutable();
455 return GeneratedMessageLite.parseUnknownField(
457 getDefaultInstanceForType(),
463 protected final void mergeExtensionFields(final MessageType other) {
464 ensureExtensionsIsMutable();
465 extensions.mergeFrom(((ExtendableMessage) other).extensions);
469 // -----------------------------------------------------------------
472 * Parse an unknown field or an extension.
473 * @return {@code true} unless the tag is an end-group tag.
475 private static <MessageType extends MessageLite>
476 boolean parseUnknownField(
477 FieldSet<ExtensionDescriptor> extensions,
478 MessageType defaultInstance,
479 CodedInputStream input,
480 ExtensionRegistryLite extensionRegistry,
481 int tag) throws IOException {
482 int wireType = WireFormat.getTagWireType(tag);
483 int fieldNumber = WireFormat.getTagFieldNumber(tag);
485 GeneratedExtension<MessageType, ?> extension =
486 extensionRegistry.findLiteExtensionByNumber(
487 defaultInstance, fieldNumber);
489 boolean unknown = false;
490 boolean packed = false;
491 if (extension == null) {
492 unknown = true; // Unknown field.
493 } else if (wireType == FieldSet.getWireFormatForFieldType(
494 extension.descriptor.getLiteType(),
495 false /* isPacked */)) {
496 packed = false; // Normal, unpacked value.
497 } else if (extension.descriptor.isRepeated &&
498 extension.descriptor.type.isPackable() &&
499 wireType == FieldSet.getWireFormatForFieldType(
500 extension.descriptor.getLiteType(),
501 true /* isPacked */)) {
502 packed = true; // Packed value.
504 unknown = true; // Wrong wire type.
507 if (unknown) { // Unknown field or wrong wire type. Skip.
508 return input.skipField(tag);
512 int length = input.readRawVarint32();
513 int limit = input.pushLimit(length);
514 if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
515 while (input.getBytesUntilLimit() > 0) {
516 int rawValue = input.readEnum();
518 extension.descriptor.getEnumType().findValueByNumber(rawValue);
520 // If the number isn't recognized as a valid value for this
521 // enum, drop it (don't even add it to unknownFields).
524 extensions.addRepeatedField(extension.descriptor, value);
527 while (input.getBytesUntilLimit() > 0) {
529 FieldSet.readPrimitiveField(input,
530 extension.descriptor.getLiteType());
531 extensions.addRepeatedField(extension.descriptor, value);
534 input.popLimit(limit);
537 switch (extension.descriptor.getLiteJavaType()) {
539 MessageLite.Builder subBuilder = null;
540 if (!extension.descriptor.isRepeated()) {
541 MessageLite existingValue =
542 (MessageLite) extensions.getField(extension.descriptor);
543 if (existingValue != null) {
544 subBuilder = existingValue.toBuilder();
547 if (subBuilder == null) {
548 subBuilder = extension.messageDefaultInstance.newBuilderForType();
550 if (extension.descriptor.getLiteType() ==
551 WireFormat.FieldType.GROUP) {
552 input.readGroup(extension.getNumber(),
553 subBuilder, extensionRegistry);
555 input.readMessage(subBuilder, extensionRegistry);
557 value = subBuilder.build();
561 int rawValue = input.readEnum();
562 value = extension.descriptor.getEnumType()
563 .findValueByNumber(rawValue);
564 // If the number isn't recognized as a valid value for this enum,
571 value = FieldSet.readPrimitiveField(input,
572 extension.descriptor.getLiteType());
576 if (extension.descriptor.isRepeated()) {
577 extensions.addRepeatedField(extension.descriptor, value);
579 extensions.setField(extension.descriptor, value);
586 // -----------------------------------------------------------------
588 /** For use by generated code only. */
589 public static <ContainingType extends MessageLite, Type>
590 GeneratedExtension<ContainingType, Type>
591 newSingularGeneratedExtension(
592 final ContainingType containingTypeDefaultInstance,
593 final Type defaultValue,
594 final MessageLite messageDefaultInstance,
595 final Internal.EnumLiteMap<?> enumTypeMap,
597 final WireFormat.FieldType type) {
598 return new GeneratedExtension<ContainingType, Type>(
599 containingTypeDefaultInstance,
601 messageDefaultInstance,
602 new ExtensionDescriptor(enumTypeMap, number, type,
603 false /* isRepeated */,
604 false /* isPacked */));
607 /** For use by generated code only. */
608 public static <ContainingType extends MessageLite, Type>
609 GeneratedExtension<ContainingType, Type>
610 newRepeatedGeneratedExtension(
611 final ContainingType containingTypeDefaultInstance,
612 final MessageLite messageDefaultInstance,
613 final Internal.EnumLiteMap<?> enumTypeMap,
615 final WireFormat.FieldType type,
616 final boolean isPacked) {
617 @SuppressWarnings("unchecked") // Subclasses ensure Type is a List
618 Type emptyList = (Type) Collections.emptyList();
619 return new GeneratedExtension<ContainingType, Type>(
620 containingTypeDefaultInstance,
622 messageDefaultInstance,
623 new ExtensionDescriptor(
624 enumTypeMap, number, type, true /* isRepeated */, isPacked));
627 private static final class ExtensionDescriptor
628 implements FieldSet.FieldDescriptorLite<
629 ExtensionDescriptor> {
630 private ExtensionDescriptor(
631 final Internal.EnumLiteMap<?> enumTypeMap,
633 final WireFormat.FieldType type,
634 final boolean isRepeated,
635 final boolean isPacked) {
636 this.enumTypeMap = enumTypeMap;
637 this.number = number;
639 this.isRepeated = isRepeated;
640 this.isPacked = isPacked;
643 private final Internal.EnumLiteMap<?> enumTypeMap;
644 private final int number;
645 private final WireFormat.FieldType type;
646 private final boolean isRepeated;
647 private final boolean isPacked;
649 public int getNumber() {
653 public WireFormat.FieldType getLiteType() {
657 public WireFormat.JavaType getLiteJavaType() {
658 return type.getJavaType();
661 public boolean isRepeated() {
665 public boolean isPacked() {
669 public Internal.EnumLiteMap<?> getEnumType() {
673 @SuppressWarnings("unchecked")
674 public MessageLite.Builder internalMergeFrom(
675 MessageLite.Builder to, MessageLite from) {
676 return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
679 public int compareTo(ExtensionDescriptor other) {
680 return number - other.number;
685 * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
687 * Users should ignore the contents of this class and only use objects of
688 * this type as parameters to extension accessors and ExtensionRegistry.add().
690 public static final class GeneratedExtension<
691 ContainingType extends MessageLite, Type> {
693 private GeneratedExtension(
694 final ContainingType containingTypeDefaultInstance,
695 final Type defaultValue,
696 final MessageLite messageDefaultInstance,
697 final ExtensionDescriptor descriptor) {
698 // Defensive checks to verify the correct initialization order of
699 // GeneratedExtensions and their related GeneratedMessages.
700 if (containingTypeDefaultInstance == null) {
701 throw new IllegalArgumentException(
702 "Null containingTypeDefaultInstance");
704 if (descriptor.getLiteType() == WireFormat.FieldType.MESSAGE &&
705 messageDefaultInstance == null) {
706 throw new IllegalArgumentException(
707 "Null messageDefaultInstance");
709 this.containingTypeDefaultInstance = containingTypeDefaultInstance;
710 this.defaultValue = defaultValue;
711 this.messageDefaultInstance = messageDefaultInstance;
712 this.descriptor = descriptor;
715 private final ContainingType containingTypeDefaultInstance;
716 private final Type defaultValue;
717 private final MessageLite messageDefaultInstance;
718 private final ExtensionDescriptor descriptor;
721 * Default instance of the type being extended, used to identify that type.
723 public ContainingType getContainingTypeDefaultInstance() {
724 return containingTypeDefaultInstance;
727 /** Get the field number. */
728 public int getNumber() {
729 return descriptor.getNumber();
733 * If the extension is an embedded message, this is the default instance of
736 public MessageLite getMessageDefaultInstance() {
737 return messageDefaultInstance;
742 * A serialized (serializable) form of the generated message. Stores the
743 * message as a class name and a byte array.
745 static final class SerializedForm implements Serializable {
746 private static final long serialVersionUID = 0L;
748 private String messageClassName;
749 private byte[] asBytes;
752 * Creates the serialized form by calling {@link com.google.protobuf.MessageLite#toByteArray}.
753 * @param regularForm the message to serialize
755 SerializedForm(MessageLite regularForm) {
756 messageClassName = regularForm.getClass().getName();
757 asBytes = regularForm.toByteArray();
761 * When read from an ObjectInputStream, this method converts this object
762 * back to the regular form. Part of Java's serialization magic.
763 * @return a GeneratedMessage of the type that was serialized
765 @SuppressWarnings("unchecked")
766 protected Object readResolve() throws ObjectStreamException {
768 Class messageClass = Class.forName(messageClassName);
769 Method newBuilder = messageClass.getMethod("newBuilder");
770 MessageLite.Builder builder =
771 (MessageLite.Builder) newBuilder.invoke(null);
772 builder.mergeFrom(asBytes);
773 return builder.buildPartial();
774 } catch (ClassNotFoundException e) {
775 throw new RuntimeException("Unable to find proto buffer class", e);
776 } catch (NoSuchMethodException e) {
777 throw new RuntimeException("Unable to find newBuilder method", e);
778 } catch (IllegalAccessException e) {
779 throw new RuntimeException("Unable to call newBuilder method", e);
780 } catch (InvocationTargetException e) {
781 throw new RuntimeException("Error calling newBuilder", e.getCause());
782 } catch (InvalidProtocolBufferException e) {
783 throw new RuntimeException("Unable to understand proto buffer", e);
789 * Replaces this object in the output stream with a serialized form.
790 * Part of Java's serialization magic. Generated sub-classes must override
791 * this method by calling {@code return super.writeReplace();}
792 * @return a SerializedForm of this message
794 protected Object writeReplace() throws ObjectStreamException {
795 return new SerializedForm(this);