package com.google.protobuf;
import static com.google.protobuf.Internal.checkNotNull;
import com.google.protobuf.LazyField.LazyIterator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>> extends Comparable<T> {
int getNumber();
WireFormat.FieldType getLiteType();
WireFormat.JavaType getLiteJavaType();
boolean isRepeated();
boolean isPacked();
Internal.EnumLiteMap<?> getEnumType();
MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from);
}
private static final int DEFAULT_FIELD_MAP_ARRAY_SIZE = 16;
private final SmallSortedMap<T, Object> fields;
private boolean isImmutable;
private boolean hasLazyField;
private FieldSet() {
this.fields = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
}
@SuppressWarnings("unused")
private FieldSet(final boolean dummy) {
this(SmallSortedMap.<T>newFieldMap(0));
makeImmutable();
}
private FieldSet(SmallSortedMap<T, Object> fields) {
this.fields = fields;
makeImmutable();
}
public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> newFieldSet() {
return new FieldSet<T>();
}
@SuppressWarnings("unchecked")
public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> emptySet() {
return DEFAULT_INSTANCE;
}
public static <T extends FieldDescriptorLite<T>> Builder<T> newBuilder() {
return new Builder<T>();
}
@SuppressWarnings("rawtypes")
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
boolean isEmpty() {
return fields.isEmpty();
}
@SuppressWarnings("unchecked")
public void makeImmutable() {
if (isImmutable) {
return;
}
fields.makeImmutable();
isImmutable = true;
}
public boolean isImmutable() {
return isImmutable;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FieldSet)) {
return false;
}
FieldSet<?> other = (FieldSet<?>) o;
return fields.equals(other.fields);
}
@Override
public int hashCode() {
return fields.hashCode();
}
@Override
public FieldSet<T> clone() {
FieldSet<T> clone = FieldSet.newFieldSet();
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
clone.setField(entry.getKey(), entry.getValue());
}
for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
clone.setField(entry.getKey(), entry.getValue());
}
clone.hasLazyField = hasLazyField;
return clone;
}
public void clear() {
fields.clear();
hasLazyField = false;
}
public Map<T, Object> getAllFields() {
if (hasLazyField) {
SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, false);
if (fields.isImmutable()) {
result.makeImmutable();
}
return result;
}
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
}
private static <T extends FieldDescriptorLite<T>> SmallSortedMap<T, Object> cloneAllFieldsMap(
SmallSortedMap<T, Object> fields, boolean copyList) {
SmallSortedMap<T, Object> result = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
cloneFieldEntry(result, fields.getArrayEntryAt(i), copyList);
}
for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
cloneFieldEntry(result, entry, copyList);
}
return result;
}
private static <T extends FieldDescriptorLite<T>> void cloneFieldEntry(
Map<T, Object> map, Map.Entry<T, Object> entry, boolean copyList) {
T key = entry.getKey();
Object value = entry.getValue();
if (value instanceof LazyField) {
map.put(key, ((LazyField) value).getValue());
} else if (copyList && value instanceof List) {
map.put(key, new ArrayList<>((List<?>) value));
} else {
map.put(key, value);
}
}
public Iterator<Map.Entry<T, Object>> iterator() {
if (hasLazyField) {
return new LazyIterator<T>(fields.entrySet().iterator());
}
return fields.entrySet().iterator();
}
Iterator<Map.Entry<T, Object>> descendingIterator() {
if (hasLazyField) {
return new LazyIterator<T>(fields.descendingEntrySet().iterator());
}
return fields.descendingEntrySet().iterator();
}
public boolean hasField(final T descriptor) {
if (descriptor.isRepeated()) {
throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
}
return fields.get(descriptor) != null;
}
public Object getField(final T descriptor) {
Object o = fields.get(descriptor);
if (o instanceof LazyField) {
return ((LazyField) o).getValue();
}
return o;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void setField(final T descriptor, Object value) {
if (descriptor.isRepeated()) {
if (!(value instanceof List)) {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
final List newList = new ArrayList();
newList.addAll((List) value);
for (final Object element : newList) {
verifyType(descriptor.getLiteType(), element);
}
value = newList;
} else {
verifyType(descriptor.getLiteType(), value);
}
if (value instanceof LazyField) {
hasLazyField = true;
}
fields.put(descriptor, value);
}
public void clearField(final T descriptor) {
fields.remove(descriptor);
if (fields.isEmpty()) {
hasLazyField = false;
}
}
public int getRepeatedFieldCount(final T descriptor) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getField(descriptor);
if (value == null) {
return 0;
} else {
return ((List<?>) value).size();
}
}
public Object getRepeatedField(final T descriptor, final int index) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getField(descriptor);
if (value == null) {
throw new IndexOutOfBoundsException();
} else {
return ((List<?>) value).get(index);
}
}
@SuppressWarnings("unchecked")
public void setRepeatedField(final T descriptor, final int index, final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object list = getField(descriptor);
if (list == null) {
throw new IndexOutOfBoundsException();
}
verifyType(descriptor.getLiteType(), value);
((List<Object>) list).set(index, value);
}
@SuppressWarnings("unchecked")
public void addRepeatedField(final T descriptor, final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"addRepeatedField() can only be called on repeated fields.");
}
verifyType(descriptor.getLiteType(), value);
final Object existingValue = getField(descriptor);
List<Object> list;
if (existingValue == null) {
list = new ArrayList<Object>();
fields.put(descriptor, list);
} else {
list = (List<Object>) existingValue;
}
list.add(value);
}
private void verifyType(final WireFormat.FieldType type, final Object value) {
if (!isValidType(type, value)) {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
private static boolean isValidType(final WireFormat.FieldType type, final Object value) {
checkNotNull(value);
switch (type.getJavaType()) {
case INT:
return value instanceof Integer;
case LONG:
return value instanceof Long;
case FLOAT:
return value instanceof Float;
case DOUBLE:
return value instanceof Double;
case BOOLEAN:
return value instanceof Boolean;
case STRING:
return value instanceof String;
case BYTE_STRING:
return value instanceof ByteString || value instanceof byte[];
case ENUM:
return (value instanceof Integer || value instanceof Internal.EnumLite);
case MESSAGE:
return (value instanceof MessageLite) || (value instanceof LazyField);
}
return false;
}
public boolean isInitialized() {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
if (!isInitialized(fields.getArrayEntryAt(i))) {
return false;
}
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
if (!isInitialized(entry)) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
private static <T extends FieldDescriptorLite<T>> boolean isInitialized(
final Map.Entry<T, Object> entry) {
final T descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
if (descriptor.isRepeated()) {
for (final MessageLite element : (List<MessageLite>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
Object value = entry.getValue();
if (value instanceof MessageLite) {
if (!((MessageLite) value).isInitialized()) {
return false;
}
} else if (value instanceof LazyField) {
return true;
} else {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
}
return true;
}
static int getWireFormatForFieldType(final WireFormat.FieldType type, boolean isPacked) {
if (isPacked) {
return WireFormat.WIRETYPE_LENGTH_DELIMITED;
} else {
return type.getWireType();
}
}
public void mergeFrom(final FieldSet<T> other) {
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
mergeFromField(other.fields.getArrayEntryAt(i));
}
for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
mergeFromField(entry);
}
}
private static Object cloneIfMutable(Object value) {
if (value instanceof byte[]) {
byte[] bytes = (byte[]) value;
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
return copy;
} else {
return value;
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void mergeFromField(final Map.Entry<T, Object> entry) {
final T descriptor = entry.getKey();
Object otherValue = entry.getValue();
if (otherValue instanceof LazyField) {
otherValue = ((LazyField) otherValue).getValue();
}
if (descriptor.isRepeated()) {
Object value = getField(descriptor);
if (value == null) {
value = new ArrayList();
}
for (Object element : (List) otherValue) {
((List) value).add(cloneIfMutable(element));
}
fields.put(descriptor, value);
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
Object value = getField(descriptor);
if (value == null) {
fields.put(descriptor, cloneIfMutable(otherValue));
} else {
value =
descriptor
.internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
.build();
fields.put(descriptor, value);
}
} else {
fields.put(descriptor, cloneIfMutable(otherValue));
}
}
public static Object readPrimitiveField(
CodedInputStream input, final WireFormat.FieldType type, boolean checkUtf8)
throws IOException {
if (checkUtf8) {
return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.STRICT);
} else {
return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.LOOSE);
}
}
public void writeTo(final CodedOutputStream output) throws IOException {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
writeField(entry.getKey(), entry.getValue(), output);
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
writeField(entry.getKey(), entry.getValue(), output);
}
}
public void writeMessageSetTo(final CodedOutputStream output) throws IOException {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
writeMessageSetTo(fields.getArrayEntryAt(i), output);
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
writeMessageSetTo(entry, output);
}
}
private void writeMessageSetTo(final Map.Entry<T, Object> entry, final CodedOutputStream output)
throws IOException {
final T descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
&& !descriptor.isRepeated()
&& !descriptor.isPacked()) {
Object value = entry.getValue();
if (value instanceof LazyField) {
value = ((LazyField) value).getValue();
}
output.writeMessageSetExtension(entry.getKey().getNumber(), (MessageLite) value);
} else {
writeField(descriptor, entry.getValue(), output);
}
}
static void writeElement(
final CodedOutputStream output,
final WireFormat.FieldType type,
final int number,
final Object value)
throws IOException {
if (type == WireFormat.FieldType.GROUP) {
output.writeGroup(number, (MessageLite) value);
} else {
output.writeTag(number, getWireFormatForFieldType(type, false));
writeElementNoTag(output, type, value);
}
}
static void writeElementNoTag(
final CodedOutputStream output, final WireFormat.FieldType type, final Object value)
throws IOException {
switch (type) {
case DOUBLE:
output.writeDoubleNoTag((Double) value);
break;
case FLOAT:
output.writeFloatNoTag((Float) value);
break;
case INT64:
output.writeInt64NoTag((Long) value);
break;
case UINT64:
output.writeUInt64NoTag((Long) value);
break;
case INT32:
output.writeInt32NoTag((Integer) value);
break;
case FIXED64:
output.writeFixed64NoTag((Long) value);
break;
case FIXED32:
output.writeFixed32NoTag((Integer) value);
break;
case BOOL:
output.writeBoolNoTag((Boolean) value);
break;
case GROUP:
output.writeGroupNoTag((MessageLite) value);
break;
case MESSAGE:
output.writeMessageNoTag((MessageLite) value);
break;
case STRING:
if (value instanceof ByteString) {
output.writeBytesNoTag((ByteString) value);
} else {
output.writeStringNoTag((String) value);
}
break;
case BYTES:
if (value instanceof ByteString) {
output.writeBytesNoTag((ByteString) value);
} else {
output.writeByteArrayNoTag((byte[]) value);
}
break;
case UINT32:
output.writeUInt32NoTag((Integer) value);
break;
case SFIXED32:
output.writeSFixed32NoTag((Integer) value);
break;
case SFIXED64:
output.writeSFixed64NoTag((Long) value);
break;
case SINT32:
output.writeSInt32NoTag((Integer) value);
break;
case SINT64:
output.writeSInt64NoTag((Long) value);
break;
case ENUM:
if (value instanceof Internal.EnumLite) {
output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
} else {
output.writeEnumNoTag(((Integer) value).intValue());
}
break;
}
}
public static void writeField(
final FieldDescriptorLite<?> descriptor, final Object value, final CodedOutputStream output)
throws IOException {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
final List<?> valueList = (List<?>) value;
if (descriptor.isPacked()) {
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
int dataSize = 0;
for (final Object element : valueList) {
dataSize += computeElementSizeNoTag(type, element);
}
output.writeRawVarint32(dataSize);
for (final Object element : valueList) {
writeElementNoTag(output, type, element);
}
} else {
for (final Object element : valueList) {
writeElement(output, type, number, element);
}
}
} else {
if (value instanceof LazyField) {
writeElement(output, type, number, ((LazyField) value).getValue());
} else {
writeElement(output, type, number, value);
}
}
}
public int getSerializedSize() {
int size = 0;
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
size += computeFieldSize(entry.getKey(), entry.getValue());
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
size += computeFieldSize(entry.getKey(), entry.getValue());
}
return size;
}
public int getMessageSetSerializedSize() {
int size = 0;
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
size += getMessageSetSerializedSize(entry);
}
return size;
}
private int getMessageSetSerializedSize(final Map.Entry<T, Object> entry) {
final T descriptor = entry.getKey();
Object value = entry.getValue();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
&& !descriptor.isRepeated()
&& !descriptor.isPacked()) {
if (value instanceof LazyField) {
return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
entry.getKey().getNumber(), (LazyField) value);
} else {
return CodedOutputStream.computeMessageSetExtensionSize(
entry.getKey().getNumber(), (MessageLite) value);
}
} else {
return computeFieldSize(descriptor, value);
}
}
static int computeElementSize(
final WireFormat.FieldType type, final int number, final Object value) {
int tagSize = CodedOutputStream.computeTagSize(number);
if (type == WireFormat.FieldType.GROUP) {
tagSize *= 2;
}
return tagSize + computeElementSizeNoTag(type, value);
}
static int computeElementSizeNoTag(final WireFormat.FieldType type, final Object value) {
switch (type) {
case DOUBLE:
return CodedOutputStream.computeDoubleSizeNoTag((Double) value);
case FLOAT:
return CodedOutputStream.computeFloatSizeNoTag((Float) value);
case INT64:
return CodedOutputStream.computeInt64SizeNoTag((Long) value);
case UINT64:
return CodedOutputStream.computeUInt64SizeNoTag((Long) value);
case INT32:
return CodedOutputStream.computeInt32SizeNoTag((Integer) value);
case FIXED64:
return CodedOutputStream.computeFixed64SizeNoTag((Long) value);
case FIXED32:
return CodedOutputStream.computeFixed32SizeNoTag((Integer) value);
case BOOL:
return CodedOutputStream.computeBoolSizeNoTag((Boolean) value);
case GROUP:
return CodedOutputStream.computeGroupSizeNoTag((MessageLite) value);
case BYTES:
if (value instanceof ByteString) {
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
} else {
return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
}
case STRING:
if (value instanceof ByteString) {
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
} else {
return CodedOutputStream.computeStringSizeNoTag((String) value);
}
case UINT32:
return CodedOutputStream.computeUInt32SizeNoTag((Integer) value);
case SFIXED32:
return CodedOutputStream.computeSFixed32SizeNoTag((Integer) value);
case SFIXED64:
return CodedOutputStream.computeSFixed64SizeNoTag((Long) value);
case SINT32:
return CodedOutputStream.computeSInt32SizeNoTag((Integer) value);
case SINT64:
return CodedOutputStream.computeSInt64SizeNoTag((Long) value);
case MESSAGE:
if (value instanceof LazyField) {
return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
} else {
return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
}
case ENUM:
if (value instanceof Internal.EnumLite) {
return CodedOutputStream.computeEnumSizeNoTag(((Internal.EnumLite) value).getNumber());
} else {
return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
}
}
throw new RuntimeException("There is no way to get here, but the compiler thinks otherwise.");
}
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor, final Object value) {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
if (descriptor.isPacked()) {
int dataSize = 0;
for (final Object element : (List<?>) value) {
dataSize += computeElementSizeNoTag(type, element);
}
return dataSize
+ CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeRawVarint32Size(dataSize);
} else {
int size = 0;
for (final Object element : (List<?>) value) {
size += computeElementSize(type, number, element);
}
return size;
}
} else {
return computeElementSize(type, number, value);
}
}
static final class Builder<T extends FieldDescriptorLite<T>> {
private SmallSortedMap<T, Object> fields;
private boolean hasLazyField;
private boolean isMutable;
private boolean hasNestedBuilders;
private Builder() {
this(SmallSortedMap.<T>newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE));
}
private Builder(SmallSortedMap<T, Object> fields) {
this.fields = fields;
this.isMutable = true;
}
public FieldSet<T> build() {
if (fields.isEmpty()) {
return FieldSet.emptySet();
}
isMutable = false;
SmallSortedMap<T, Object> fieldsForBuild = fields;
if (hasNestedBuilders) {
fieldsForBuild = cloneAllFieldsMap(fields, false);
replaceBuilders(fieldsForBuild);
}
FieldSet<T> fieldSet = new FieldSet<>(fieldsForBuild);
fieldSet.hasLazyField = hasLazyField;
return fieldSet;
}
private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
SmallSortedMap<T, Object> fieldMap) {
for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
replaceBuilders(fieldMap.getArrayEntryAt(i));
}
for (Map.Entry<T, Object> entry : fieldMap.getOverflowEntries()) {
replaceBuilders(entry);
}
}
private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
Map.Entry<T, Object> entry) {
entry.setValue(replaceBuilders(entry.getKey(), entry.getValue()));
}
private static <T extends FieldDescriptorLite<T>> Object replaceBuilders(
T descriptor, Object value) {
if (value == null) {
return value;
}
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
if (descriptor.isRepeated()) {
if (!(value instanceof List)) {
throw new IllegalStateException(
"Repeated field should contains a List but actually contains type: "
+ value.getClass());
}
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>) value;
for (int i = 0; i < list.size(); i++) {
Object oldElement = list.get(i);
Object newElement = replaceBuilder(oldElement);
if (newElement != oldElement) {
if (list == value) {
list = new ArrayList<>(list);
}
list.set(i, newElement);
}
}
return list;
} else {
return replaceBuilder(value);
}
}
return value;
}
private static Object replaceBuilder(Object value) {
return (value instanceof MessageLite.Builder) ? ((MessageLite.Builder) value).build() : value;
}
public static <T extends FieldDescriptorLite<T>> Builder<T> fromFieldSet(FieldSet<T> fieldSet) {
Builder<T> builder = new Builder<T>(cloneAllFieldsMap(fieldSet.fields, true));
builder.hasLazyField = fieldSet.hasLazyField;
return builder;
}
public Map<T, Object> getAllFields() {
if (hasLazyField) {
SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, false);
if (fields.isImmutable()) {
result.makeImmutable();
} else {
replaceBuilders(result);
}
return result;
}
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
}
public boolean hasField(final T descriptor) {
if (descriptor.isRepeated()) {
throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
}
return fields.get(descriptor) != null;
}
public Object getField(final T descriptor) {
Object value = getFieldAllowBuilders(descriptor);
return replaceBuilders(descriptor, value);
}
Object getFieldAllowBuilders(final T descriptor) {
Object o = fields.get(descriptor);
if (o instanceof LazyField) {
return ((LazyField) o).getValue();
}
return o;
}
private void ensureIsMutable() {
if (!isMutable) {
fields = cloneAllFieldsMap(fields, true);
isMutable = true;
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void setField(final T descriptor, Object value) {
ensureIsMutable();
if (descriptor.isRepeated()) {
if (!(value instanceof List)) {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
final List newList = new ArrayList();
newList.addAll((List) value);
for (final Object element : newList) {
verifyType(descriptor.getLiteType(), element);
hasNestedBuilders = hasNestedBuilders || element instanceof MessageLite.Builder;
}
value = newList;
} else {
verifyType(descriptor.getLiteType(), value);
}
if (value instanceof LazyField) {
hasLazyField = true;
}
hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
fields.put(descriptor, value);
}
public void clearField(final T descriptor) {
ensureIsMutable();
fields.remove(descriptor);
if (fields.isEmpty()) {
hasLazyField = false;
}
}
public int getRepeatedFieldCount(final T descriptor) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getField(descriptor);
if (value == null) {
return 0;
} else {
return ((List<?>) value).size();
}
}
public Object getRepeatedField(final T descriptor, final int index) {
if (hasNestedBuilders) {
ensureIsMutable();
}
Object value = getRepeatedFieldAllowBuilders(descriptor, index);
return replaceBuilder(value);
}
Object getRepeatedFieldAllowBuilders(final T descriptor, final int index) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getFieldAllowBuilders(descriptor);
if (value == null) {
throw new IndexOutOfBoundsException();
} else {
return ((List<?>) value).get(index);
}
}
@SuppressWarnings("unchecked")
public void setRepeatedField(final T descriptor, final int index, final Object value) {
ensureIsMutable();
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
final Object list = getField(descriptor);
if (list == null) {
throw new IndexOutOfBoundsException();
}
verifyType(descriptor.getLiteType(), value);
((List<Object>) list).set(index, value);
}
@SuppressWarnings("unchecked")
public void addRepeatedField(final T descriptor, final Object value) {
ensureIsMutable();
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"addRepeatedField() can only be called on repeated fields.");
}
hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
verifyType(descriptor.getLiteType(), value);
final Object existingValue = getField(descriptor);
List<Object> list;
if (existingValue == null) {
list = new ArrayList<>();
fields.put(descriptor, list);
} else {
list = (List<Object>) existingValue;
}
list.add(value);
}
private static void verifyType(final WireFormat.FieldType type, final Object value) {
if (!FieldSet.isValidType(type, value)) {
if (type.getJavaType() == WireFormat.JavaType.MESSAGE
&& value instanceof MessageLite.Builder) {
return;
}
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
public boolean isInitialized() {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
if (!FieldSet.isInitialized(fields.getArrayEntryAt(i))) {
return false;
}
}
for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
if (!FieldSet.isInitialized(entry)) {
return false;
}
}
return true;
}
public void mergeFrom(final FieldSet<T> other) {
ensureIsMutable();
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
mergeFromField(other.fields.getArrayEntryAt(i));
}
for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
mergeFromField(entry);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void mergeFromField(final Map.Entry<T, Object> entry) {
final T descriptor = entry.getKey();
Object otherValue = entry.getValue();
if (otherValue instanceof LazyField) {
otherValue = ((LazyField) otherValue).getValue();
}
if (descriptor.isRepeated()) {
Object value = getField(descriptor);
if (value == null) {
value = new ArrayList();
}
for (Object element : (List) otherValue) {
((List) value).add(FieldSet.cloneIfMutable(element));
}
fields.put(descriptor, value);
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
Object value = getField(descriptor);
if (value == null) {
fields.put(descriptor, FieldSet.cloneIfMutable(otherValue));
} else {
if (value instanceof MessageLite.Builder) {
descriptor.internalMergeFrom((MessageLite.Builder) value, (MessageLite) otherValue);
} else {
value =
descriptor
.internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
.build();
fields.put(descriptor, value);
}
}
} else {
fields.put(descriptor, cloneIfMutable(otherValue));
}
}
}
}