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;
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) {
for (final Descriptors.FieldDescriptor field : message.getDescriptorForType().getFields()) {
if (field.isRequired()) {
if (!message.hasField(field)) {
return false;
}
}
}
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);
}
}
}
}
}
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
}
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);
public Object getField(Descriptors.FieldDescriptor field);
boolean hasField(Descriptors.FieldDescriptor field);
MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
MergeTarget clearField(Descriptors.FieldDescriptor field);
MergeTarget setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value);
boolean hasOneof(Descriptors.OneofDescriptor oneof);
MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
Object parseGroup(
CodedInputStream input,
ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor,
Message defaultInstance)
throws IOException;
Object parseMessage(
CodedInputStream input,
ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor,
Message defaultInstance)
throws IOException;
Object parseMessageFromBytes(
ByteString bytes,
ExtensionRegistryLite registry,
Descriptors.FieldDescriptor descriptor,
Message defaultInstance)
throws IOException;
WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor);
MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance);
MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance);
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;
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;
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;
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) {
Message.Builder subBuilder;
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);
}
}
return new BuilderAdapter(subBuilder);
}
@Override
public MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor field, Message defaultInstance) {
Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
return new BuilderAdapter(subBuilder);
}
@Override
public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) {
return WireFormat.Utf8Validation.STRICT;
}
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) {
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 MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object");
}
@Override
public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) {
return WireFormat.Utf8Validation.STRICT;
}
return WireFormat.Utf8Validation.LOOSE;
}
@Override
public Object finish() {
throw new UnsupportedOperationException("finish() called on FieldSet object");
}
}
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)) {
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;
} else if (wireType
== FieldSet.getWireFormatForFieldType(field.getLiteType(), false)) {
packed = false;
} else if (field.isPackable()
&& wireType
== FieldSet.getWireFormatForFieldType(field.getLiteType(), true)) {
packed = true;
} else {
unknown = true;
}
if (unknown) {
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 (unknownFields != null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
}
} else {
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 (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;
}
private static void mergeMessageSetExtensionFromCodedStream(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptors.Descriptor type,
MergeTarget target)
throws IOException {
int typeId = 0;
ByteString rawBytes = null;
ExtensionRegistry.ExtensionInfo extension = null;
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) {
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()) {
eagerlyMergeMessageSetExtension(input, extension, extensionRegistry, target);
rawBytes = null;
continue;
}
}
rawBytes = input.readBytes();
} else {
if (!input.skipField(tag)) {
break;
}
}
}
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
if (rawBytes != null && typeId != 0) {
if (extension != null) {
mergeMessageSetExtensionFromBytes(rawBytes, extension, extensionRegistry, target);
} else {
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()) {
Object value =
target.parseMessageFromBytes(
rawBytes, extensionRegistry, field, extension.defaultInstance);
target.setField(field, value);
} else {
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);
}
}