// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.
Descriptors.
FieldDescriptor;
import java.io.
IOException;
import java.util.
ArrayList;
import java.util.
List;
import java.util.
Map;
import java.util.
TreeMap;
/**
* Reflection utility methods shared by both mutable and immutable messages.
*
* @author liujisi@google.com (Pherl Liu)
*/
class
MessageReflection {
static void
writeMessageTo(
Message message,
Map<
FieldDescriptor,
Object>
fields,
CodedOutputStream output,
boolean
alwaysWriteRequiredFields)
throws
IOException {
final boolean
isMessageSet =
message.
getDescriptorForType().
getOptions().
getMessageSetWireFormat();
if (
alwaysWriteRequiredFields) {
fields = new
TreeMap<
FieldDescriptor,
Object>(
fields);
for (final
FieldDescriptor field :
message.
getDescriptorForType().
getFields()) {
if (
field.
isRequired() && !
fields.
containsKey(
field)) {
fields.
put(
field,
message.
getField(
field));
}
}
}
for (final
Map.
Entry<
Descriptors.
FieldDescriptor,
Object>
entry :
fields.
entrySet()) {
final
Descriptors.
FieldDescriptor field =
entry.
getKey();
final
Object value =
entry.
getValue();
if (
isMessageSet &&
field.
isExtension() &&
field.
getType() ==
Descriptors.
FieldDescriptor.
Type.
MESSAGE &&
!
field.
isRepeated()) {
output.
writeMessageSetExtension(
field.
getNumber(), (
Message)
value);
} else {
FieldSet.
writeField(
field,
value,
output);
}
}
final
UnknownFieldSet unknownFields =
message.
getUnknownFields();
if (
isMessageSet) {
unknownFields.
writeAsMessageSetTo(
output);
} else {
unknownFields.
writeTo(
output);
}
}
static int
getSerializedSize(
Message message,
Map<
FieldDescriptor,
Object>
fields) {
int
size = 0;
final boolean
isMessageSet =
message.
getDescriptorForType().
getOptions().
getMessageSetWireFormat();
for (final
Map.
Entry<
Descriptors.
FieldDescriptor,
Object>
entry :
fields.
entrySet()) {
final
Descriptors.
FieldDescriptor field =
entry.
getKey();
final
Object value =
entry.
getValue();
if (
isMessageSet &&
field.
isExtension() &&
field.
getType() ==
Descriptors.
FieldDescriptor.
Type.
MESSAGE &&
!
field.
isRepeated()) {
size +=
CodedOutputStream.
computeMessageSetExtensionSize(
field.
getNumber(), (
Message)
value);
} else {
size +=
FieldSet.
computeFieldSize(
field,
value);
}
}
final
UnknownFieldSet unknownFields =
message.
getUnknownFields();
if (
isMessageSet) {
size +=
unknownFields.
getSerializedSizeAsMessageSet();
} else {
size +=
unknownFields.
getSerializedSize();
}
return
size;
}
static
String delimitWithCommas(
List<
String>
parts) {
StringBuilder result = new
StringBuilder();
for (
String part :
parts) {
if (
result.
length() > 0) {
result.
append(", ");
}
result.
append(
part);
}
return
result.
toString();
}
@
SuppressWarnings("unchecked")
static boolean
isInitialized(
MessageOrBuilder message) {
// Check that all required fields are present.
for (final
Descriptors.
FieldDescriptor field :
message
.
getDescriptorForType()
.
getFields()) {
if (
field.
isRequired()) {
if (!
message.
hasField(
field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
for (final
Map.
Entry<
Descriptors.
FieldDescriptor,
Object>
entry :
message.
getAllFields().
entrySet()) {
final
Descriptors.
FieldDescriptor field =
entry.
getKey();
if (
field.
getJavaType() ==
Descriptors.
FieldDescriptor.
JavaType.
MESSAGE) {
if (
field.
isRepeated()) {
for (final
Message element
: (
List<
Message>)
entry.
getValue()) {
if (!
element.
isInitialized()) {
return false;
}
}
} else {
if (!((
Message)
entry.
getValue()).
isInitialized()) {
return false;
}
}
}
}
return true;
}
private static
String subMessagePrefix(final
String prefix,
final
Descriptors.
FieldDescriptor field,
final int
index) {
final
StringBuilder result = new
StringBuilder(
prefix);
if (
field.
isExtension()) {
result.
append('(')
.
append(
field.
getFullName())
.
append(')');
} else {
result.
append(
field.
getName());
}
if (
index != -1) {
result.
append('[')
.
append(
index)
.
append(']');
}
result.
append('.');
return
result.
toString();
}
private static void
findMissingFields(final
MessageOrBuilder message,
final
String prefix,
final
List<
String>
results) {
for (final
Descriptors.
FieldDescriptor field :
message.
getDescriptorForType().
getFields()) {
if (
field.
isRequired() && !
message.
hasField(
field)) {
results.
add(
prefix +
field.
getName());
}
}
for (final
Map.
Entry<
Descriptors.
FieldDescriptor,
Object>
entry :
message.
getAllFields().
entrySet()) {
final
Descriptors.
FieldDescriptor field =
entry.
getKey();
final
Object value =
entry.
getValue();
if (
field.
getJavaType() ==
Descriptors.
FieldDescriptor.
JavaType.
MESSAGE) {
if (
field.
isRepeated()) {
int
i = 0;
for (final
Object element : (
List)
value) {
findMissingFields((
MessageOrBuilder)
element,
subMessagePrefix(
prefix,
field,
i++),
results);
}
} else {
if (
message.
hasField(
field)) {
findMissingFields((
MessageOrBuilder)
value,
subMessagePrefix(
prefix,
field, -1),
results);
}
}
}
}
}
/**
* Populates {@code this.missingFields} with the full "path" of each missing
* required field in the given message.
*/
static
List<
String>
findMissingFields(
final
MessageOrBuilder message) {
final
List<
String>
results = new
ArrayList<
String>();
findMissingFields(
message, "",
results);
return
results;
}
static interface
MergeTarget {
enum
ContainerType {
MESSAGE, EXTENSION_SET
}
/**
* Returns the descriptor for the target.
*/
public
Descriptors.
Descriptor getDescriptorForType();
public
ContainerType getContainerType();
public
ExtensionRegistry.
ExtensionInfo findExtensionByName(
ExtensionRegistry registry,
String name);
public
ExtensionRegistry.
ExtensionInfo findExtensionByNumber(
ExtensionRegistry registry,
Descriptors.
Descriptor containingType,
int
fieldNumber);
/**
* Obtains the value of the given field, or the default value if it is not
* set. For primitive fields, the boxed primitive value is returned. For
* enum fields, the EnumValueDescriptor for the value is returned. For
* embedded message fields, the sub-message is returned. For repeated
* fields, a java.util.List is returned.
*/
public
Object getField(
Descriptors.
FieldDescriptor field);
/**
* Returns true if the given field is set. This is exactly equivalent to
* calling the generated "has" accessor method corresponding to the field.
*
* @throws IllegalArgumentException The field is a repeated field, or {@code
* field.getContainingType() != getDescriptorForType()}.
*/
boolean
hasField(
Descriptors.
FieldDescriptor field);
/**
* Sets a field to the given value. The value must be of the correct type
* for this field, i.e. the same type that
* {@link Message#getField(Descriptors.FieldDescriptor)}
* would return.
*/
MergeTarget setField(
Descriptors.
FieldDescriptor field,
Object value);
/**
* Clears the field. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the field.
*/
MergeTarget clearField(
Descriptors.
FieldDescriptor field);
/**
* Sets an element of a repeated field to the given value. The value must
* be of the correct type for this field, i.e. the same type that {@link
* Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
*
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() !=
* getDescriptorForType()}.
*/
MergeTarget setRepeatedField(
Descriptors.
FieldDescriptor field,
int
index,
Object value);
/**
* Like {@code setRepeatedField}, but appends the value as a new element.
*
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() !=
* getDescriptorForType()}.
*/
MergeTarget addRepeatedField(
Descriptors.
FieldDescriptor field,
Object value);
/**
* Returns true if the given oneof is set.
*
* @throws IllegalArgumentException if
* {@code oneof.getContainingType() != getDescriptorForType()}.
*/
boolean
hasOneof(
Descriptors.
OneofDescriptor oneof);
/**
* Clears the oneof. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the oneof.
*/
MergeTarget clearOneof(
Descriptors.
OneofDescriptor oneof);
/**
* Obtains the FieldDescriptor if the given oneof is set. Returns null
* if no field is set.
*/
Descriptors.
FieldDescriptor getOneofFieldDescriptor(
Descriptors.
OneofDescriptor oneof);
/**
* Parse the input stream into a sub field group defined based on either
* FieldDescriptor or the default instance.
*/
Object parseGroup(
CodedInputStream input,
ExtensionRegistryLite registry,
Descriptors.
FieldDescriptor descriptor,
Message defaultInstance)
throws
IOException;
/**
* Parse the input stream into a sub field message defined based on either
* FieldDescriptor or the default instance.
*/
Object parseMessage(
CodedInputStream input,
ExtensionRegistryLite registry,
Descriptors.
FieldDescriptor descriptor,
Message defaultInstance)
throws
IOException;
/**
* Parse from a ByteString into a sub field message defined based on either
* FieldDescriptor or the default instance. There isn't a varint indicating
* the length of the message at the beginning of the input ByteString.
*/
Object parseMessageFromBytes(
ByteString bytes,
ExtensionRegistryLite registry,
Descriptors.
FieldDescriptor descriptor,
Message defaultInstance)
throws
IOException;
/**
* Returns the UTF8 validation level for the field.
*/
WireFormat.
Utf8Validation getUtf8Validation(
Descriptors.
FieldDescriptor
descriptor);
/**
* Returns a new merge target for a sub-field. When defaultInstance is
* provided, it indicates the descriptor is for an extension type, and
* implementations should create a new instance from the defaultInstance
* prototype directly.
*/
MergeTarget newMergeTargetForField(
Descriptors.
FieldDescriptor descriptor,
Message defaultInstance);
/**
* Finishes the merge and returns the underlying object.
*/
Object finish();
}
static class
BuilderAdapter implements
MergeTarget {
private final
Message.
Builder builder;
@
Override
public
Descriptors.
Descriptor getDescriptorForType() {
return
builder.
getDescriptorForType();
}
public
BuilderAdapter(
Message.
Builder builder) {
this.
builder =
builder;
}
@
Override
public
Object getField(
Descriptors.
FieldDescriptor field) {
return
builder.
getField(
field);
}
@
Override
public boolean
hasField(
Descriptors.
FieldDescriptor field) {
return
builder.
hasField(
field);
}
@
Override
public
MergeTarget setField(
Descriptors.
FieldDescriptor field,
Object value) {
builder.
setField(
field,
value);
return this;
}
@
Override
public
MergeTarget clearField(
Descriptors.
FieldDescriptor field) {
builder.
clearField(
field);
return this;
}
@
Override
public
MergeTarget setRepeatedField(
Descriptors.
FieldDescriptor field, int
index,
Object value) {
builder.
setRepeatedField(
field,
index,
value);
return this;
}
@
Override
public
MergeTarget addRepeatedField(
Descriptors.
FieldDescriptor field,
Object value) {
builder.
addRepeatedField(
field,
value);
return this;
}
@
Override
public boolean
hasOneof(
Descriptors.
OneofDescriptor oneof) {
return
builder.
hasOneof(
oneof);
}
@
Override
public
MergeTarget clearOneof(
Descriptors.
OneofDescriptor oneof) {
builder.
clearOneof(
oneof);
return this;
}
@
Override
public
Descriptors.
FieldDescriptor getOneofFieldDescriptor(
Descriptors.
OneofDescriptor oneof) {
return
builder.
getOneofFieldDescriptor(
oneof);
}
@
Override
public
ContainerType getContainerType() {
return
ContainerType.
MESSAGE;
}
@
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 extensionRegistry,
Descriptors.
FieldDescriptor field,
Message defaultInstance)
throws
IOException {
Message.
Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (
defaultInstance != null) {
subBuilder =
defaultInstance.
newBuilderForType();
} else {
subBuilder =
builder.
newBuilderForField(
field);
}
if (!
field.
isRepeated()) {
Message originalMessage = (
Message)
getField(
field);
if (
originalMessage != null) {
subBuilder.
mergeFrom(
originalMessage);
}
}
input.
readGroup(
field.
getNumber(),
subBuilder,
extensionRegistry);
return
subBuilder.
buildPartial();
}
@
Override
public
Object parseMessage(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
Descriptors.
FieldDescriptor field,
Message defaultInstance)
throws
IOException {
Message.
Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (
defaultInstance != null) {
subBuilder =
defaultInstance.
newBuilderForType();
} else {
subBuilder =
builder.
newBuilderForField(
field);
}
if (!
field.
isRepeated()) {
Message originalMessage = (
Message)
getField(
field);
if (
originalMessage != null) {
subBuilder.
mergeFrom(
originalMessage);
}
}
input.
readMessage(
subBuilder,
extensionRegistry);
return
subBuilder.
buildPartial();
}
@
Override
public
Object parseMessageFromBytes(
ByteString bytes,
ExtensionRegistryLite extensionRegistry,
Descriptors.
FieldDescriptor field,
Message defaultInstance)
throws
IOException {
Message.
Builder subBuilder;
// When default instance is not null. The field is an extension field.
if (
defaultInstance != null) {
subBuilder =
defaultInstance.
newBuilderForType();
} else {
subBuilder =
builder.
newBuilderForField(
field);
}
if (!
field.
isRepeated()) {
Message originalMessage = (
Message)
getField(
field);
if (
originalMessage != null) {
subBuilder.
mergeFrom(
originalMessage);
}
}
subBuilder.
mergeFrom(
bytes,
extensionRegistry);
return
subBuilder.
buildPartial();
}
@
Override
public
MergeTarget newMergeTargetForField(
Descriptors.
FieldDescriptor field,
Message defaultInstance) {
if (
defaultInstance != null) {
return new
BuilderAdapter(
defaultInstance.
newBuilderForType());
} else {
return new
BuilderAdapter(
builder.
newBuilderForField(
field));
}
}
@
Override
public
WireFormat.
Utf8Validation getUtf8Validation(
Descriptors.
FieldDescriptor descriptor) {
if (
descriptor.
needsUtf8Check()) {
return
WireFormat.
Utf8Validation.
STRICT;
}
// TODO(liujisi): support lazy strings for repeated fields.
if (!
descriptor.
isRepeated()
&&
builder instanceof
GeneratedMessage.
Builder) {
return
WireFormat.
Utf8Validation.
LAZY;
}
return
WireFormat.
Utf8Validation.
LOOSE;
}
@
Override
public
Object finish() {
return
builder.
buildPartial();
}
}
static class
ExtensionAdapter implements
MergeTarget {
private final
FieldSet<
Descriptors.
FieldDescriptor>
extensions;
ExtensionAdapter(
FieldSet<
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
public
MergeTarget setField(
Descriptors.
FieldDescriptor field,
Object value) {
extensions.
setField(
field,
value);
return this;
}
@
Override
public
MergeTarget clearField(
Descriptors.
FieldDescriptor field) {
extensions.
clearField(
field);
return this;
}
@
Override
public
MergeTarget setRepeatedField(
Descriptors.
FieldDescriptor field, int
index,
Object value) {
extensions.
setRepeatedField(
field,
index,
value);
return this;
}
@
Override
public
MergeTarget addRepeatedField(
Descriptors.
FieldDescriptor field,
Object value) {
extensions.
addRepeatedField(
field,
value);
return this;
}
@
Override
public boolean
hasOneof(
Descriptors.
OneofDescriptor oneof) {
return false;
}
@
Override
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
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
WireFormat.
Utf8Validation getUtf8Validation(
Descriptors.
FieldDescriptor descriptor) {
if (
descriptor.
needsUtf8Check()) {
return
WireFormat.
Utf8Validation.
STRICT;
}
// TODO(liujisi): support lazy strings for ExtesnsionSet.
return
WireFormat.
Utf8Validation.
LOOSE;
}
@
Override
public
Object finish() {
throw new
UnsupportedOperationException(
"finish() called on FieldSet object");
}
}
/**
* Parses a single field into MergeTarget. The target can be Message.Builder, FieldSet or
* MutableMessage.
*
* <p>Package-private because it is used by GeneratedMessage.ExtendableMessage.
*
* @param tag The tag, which should have already been read.
* @param unknownFields If not null, unknown fields will be merged to this {@link
* UnknownFieldSet}, otherwise unknown fields will be discarded.
* @return {@code true} unless the tag is an end-group tag.
*/
static boolean
mergeFieldFrom(
CodedInputStream input,
UnknownFieldSet.
Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptors.
Descriptor type,
MergeTarget target,
int
tag)
throws
IOException {
if (
type.
getOptions().
getMessageSetWireFormat() &&
tag ==
WireFormat.
MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
input,
unknownFields,
extensionRegistry,
type,
target);
return true;
}
final int
wireType =
WireFormat.
getTagWireType(
tag);
final int
fieldNumber =
WireFormat.
getTagFieldNumber(
tag);
final
Descriptors.
FieldDescriptor field;
Message defaultInstance = null;
if (
type.
isExtensionNumber(
fieldNumber)) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (
extensionRegistry instanceof
ExtensionRegistry) {
final
ExtensionRegistry.
ExtensionInfo extension =
target.
findExtensionByNumber((
ExtensionRegistry)
extensionRegistry,
type,
fieldNumber);
if (
extension == null) {
field = null;
} else {
field =
extension.
descriptor;
defaultInstance =
extension.
defaultInstance;
if (
defaultInstance == null &&
field.
getJavaType()
==
Descriptors.
FieldDescriptor.
JavaType.
MESSAGE) {
throw new
IllegalStateException(
"Message-typed extension lacked default instance: " +
field.
getFullName());
}
}
} else {
field = null;
}
} else if (
target.
getContainerType() ==
MergeTarget.
ContainerType.
MESSAGE) {
field =
type.
findFieldByNumber(
fieldNumber);
} else {
field = null;
}
boolean
unknown = false;
boolean
packed = false;
if (
field == null) {
unknown = true; // Unknown field.
} else if (
wireType ==
FieldSet.
getWireFormatForFieldType(
field.
getLiteType(),
false /* isPacked */)) {
packed = false;
} else if (
field.
isPackable() &&
wireType ==
FieldSet.
getWireFormatForFieldType(
field.
getLiteType(),
true /* isPacked */)) {
packed = true;
} else {
unknown = true; // Unknown wire type.
}
if (
unknown) { // Unknown field or wrong wire type. Skip.
if (
unknownFields != null) {
return
unknownFields.
mergeFieldFrom(
tag,
input);
} else {
return
input.
skipField(
tag);
}
}
if (
packed) {
final int
length =
input.
readRawVarint32();
final int
limit =
input.
pushLimit(
length);
if (
field.
getLiteType() ==
WireFormat.
FieldType.
ENUM) {
while (
input.
getBytesUntilLimit() > 0) {
final int
rawValue =
input.
readEnum();
if (
field.
getFile().
supportsUnknownEnumValue()) {
target.
addRepeatedField(
field,
field.
getEnumType().
findValueByNumberCreatingIfUnknown(
rawValue));
} else {
final
Object value =
field.
getEnumType().
findValueByNumber(
rawValue);
if (
value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
target.
addRepeatedField(
field,
value);
}
}
} else {
while (
input.
getBytesUntilLimit() > 0) {
final
Object value =
WireFormat.
readPrimitiveField(
input,
field.
getLiteType(),
target.
getUtf8Validation(
field));
target.
addRepeatedField(
field,
value);
}
}
input.
popLimit(
limit);
} else {
final
Object value;
switch (
field.
getType()) {
case
GROUP: {
value =
target
.
parseGroup(
input,
extensionRegistry,
field,
defaultInstance);
break;
}
case
MESSAGE: {
value =
target
.
parseMessage(
input,
extensionRegistry,
field,
defaultInstance);
break;
}
case
ENUM:
final int
rawValue =
input.
readEnum();
if (
field.
getFile().
supportsUnknownEnumValue()) {
value =
field.
getEnumType().
findValueByNumberCreatingIfUnknown(
rawValue);
} else {
value =
field.
getEnumType().
findValueByNumber(
rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (
value == null) {
if (
unknownFields != null) {
unknownFields.
mergeVarintField(
fieldNumber,
rawValue);
}
return true;
}
}
break;
default:
value =
WireFormat.
readPrimitiveField(
input,
field.
getLiteType(),
target.
getUtf8Validation(
field));
break;
}
if (
field.
isRepeated()) {
target.
addRepeatedField(
field,
value);
} else {
target.
setField(
field,
value);
}
}
return true;
}
/**
* Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
* MergeTarget.
*/
private static void
mergeMessageSetExtensionFromCodedStream(
CodedInputStream input,
UnknownFieldSet.
Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptors.
Descriptor type,
MergeTarget target) throws
IOException {
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int
typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
ExtensionRegistry.
ExtensionInfo extension = null;
// Read bytes from input, if we get it's type first then parse it eagerly,
// otherwise we store the raw bytes in a local variable.
while (true) {
final int
tag =
input.
readTag();
if (
tag == 0) {
break;
}
if (
tag ==
WireFormat.
MESSAGE_SET_TYPE_ID_TAG) {
typeId =
input.
readUInt32();
if (
typeId != 0) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (
extensionRegistry instanceof
ExtensionRegistry) {
extension =
target.
findExtensionByNumber(
(
ExtensionRegistry)
extensionRegistry,
type,
typeId);
}
}
} else if (
tag ==
WireFormat.
MESSAGE_SET_MESSAGE_TAG) {
if (
typeId != 0) {
if (
extension != null &&
ExtensionRegistryLite.
isEagerlyParseMessageSets()) {
// We already know the type, so we can parse directly from the
// input with no copying. Hooray!
eagerlyMergeMessageSetExtension(
input,
extension,
extensionRegistry,
target);
rawBytes = null;
continue;
}
}
// We haven't seen a type ID yet or we want parse message lazily.
rawBytes =
input.
readBytes();
} else { // Unknown tag. Skip it.
if (!
input.
skipField(
tag)) {
break; // End of group
}
}
}
input.
checkLastTagWas(
WireFormat.
MESSAGE_SET_ITEM_END_TAG);
// Process the raw bytes.
if (
rawBytes != null &&
typeId != 0) { // Zero is not a valid type ID.
if (
extension != null) { // We known the type
mergeMessageSetExtensionFromBytes(
rawBytes,
extension,
extensionRegistry,
target);
} else { // We don't know how to parse this. Ignore it.
if (
rawBytes != null &&
unknownFields != null) {
unknownFields.
mergeField(
typeId,
UnknownFieldSet.
Field.
newBuilder()
.
addLengthDelimited(
rawBytes).
build());
}
}
}
}
private static void
mergeMessageSetExtensionFromBytes(
ByteString rawBytes,
ExtensionRegistry.
ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
MergeTarget target) throws
IOException {
Descriptors.
FieldDescriptor field =
extension.
descriptor;
boolean
hasOriginalValue =
target.
hasField(
field);
if (
hasOriginalValue ||
ExtensionRegistryLite.
isEagerlyParseMessageSets()) {
// If the field already exists, we just parse the field.
Object value =
target.
parseMessageFromBytes(
rawBytes,
extensionRegistry,
field,
extension.
defaultInstance);
target.
setField(
field,
value);
} else {
// Use LazyField to load MessageSet lazily.
LazyField lazyField = new
LazyField(
extension.
defaultInstance,
extensionRegistry,
rawBytes);
target.
setField(
field,
lazyField);
}
}
private static void
eagerlyMergeMessageSetExtension(
CodedInputStream input,
ExtensionRegistry.
ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
MergeTarget target) throws
IOException {
Descriptors.
FieldDescriptor field =
extension.
descriptor;
Object value =
target.
parseMessage(
input,
extensionRegistry,
field,
extension.
defaultInstance);
target.
setField(
field,
value);
}
}