// 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.
Descriptor;
import com.google.protobuf.
Descriptors.
EnumValueDescriptor;
import com.google.protobuf.
Descriptors.
FieldDescriptor;
import java.io.
IOException;
import java.util.
Collections;
import java.util.
Map;
import java.util.
TreeMap;
/**
* Implements MapEntry messages.
*
* In reflection API, map fields will be treated as repeated message fields and
* each map entry is accessed as a message. This MapEntry class is used to
* represent these map entry messages in reflection API.
*
* Protobuf internal. Users shouldn't use this class.
*/
public final class
MapEntry<K, V> extends
AbstractMessage {
private static final class
Metadata<K, V> extends
MapEntryLite.
Metadata<K, V> {
public final
Descriptor descriptor;
public final
Parser<
MapEntry<K, V>>
parser;
public
Metadata(
Descriptor descriptor,
MapEntry<K, V>
defaultInstance,
WireFormat.
FieldType keyType,
WireFormat.
FieldType valueType) {
super(
keyType,
defaultInstance.
key,
valueType,
defaultInstance.
value);
this.
descriptor =
descriptor;
this.
parser = new
AbstractParser<
MapEntry<K, V>>() {
@
Override
public
MapEntry<K, V>
parsePartialFrom(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws
InvalidProtocolBufferException {
return new
MapEntry<K, V>(
Metadata.this,
input,
extensionRegistry);
}
};
}
}
private final K
key;
private final V
value;
private final
Metadata<K, V>
metadata;
/** Create a default MapEntry instance. */
private
MapEntry(
Descriptor descriptor,
WireFormat.
FieldType keyType, K
defaultKey,
WireFormat.
FieldType valueType, V
defaultValue) {
this.
key =
defaultKey;
this.
value =
defaultValue;
this.
metadata = new
Metadata<K, V>(
descriptor, this,
keyType,
valueType);
}
/** Create a MapEntry with the provided key and value. */
@
SuppressWarnings("unchecked")
private
MapEntry(
Metadata metadata, K
key, V
value) {
this.
key =
key;
this.
value =
value;
this.
metadata =
metadata;
}
/** Parsing constructor. */
private
MapEntry(
Metadata<K, V>
metadata,
CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws
InvalidProtocolBufferException {
try {
this.
metadata =
metadata;
Map.
Entry<K, V>
entry =
MapEntryLite.
parseEntry(
input,
metadata,
extensionRegistry);
this.
key =
entry.
getKey();
this.
value =
entry.
getValue();
} catch (
InvalidProtocolBufferException e) {
throw
e.
setUnfinishedMessage(this);
} catch (
IOException e) {
throw new
InvalidProtocolBufferException(
e).
setUnfinishedMessage(this);
}
}
/**
* Create a default MapEntry instance. A default MapEntry instance should be
* created only once for each map entry message type. Generated code should
* store the created default instance and use it later to create new MapEntry
* messages of the same type.
*/
public static <K, V>
MapEntry<K, V>
newDefaultInstance(
Descriptor descriptor,
WireFormat.
FieldType keyType, K
defaultKey,
WireFormat.
FieldType valueType, V
defaultValue) {
return new
MapEntry<K, V>(
descriptor,
keyType,
defaultKey,
valueType,
defaultValue);
}
public K
getKey() {
return
key;
}
public V
getValue() {
return
value;
}
private volatile int
cachedSerializedSize = -1;
@
Override
public int
getSerializedSize() {
if (
cachedSerializedSize != -1) {
return
cachedSerializedSize;
}
int
size =
MapEntryLite.
computeSerializedSize(
metadata,
key,
value);
cachedSerializedSize =
size;
return
size;
}
@
Override
public void
writeTo(
CodedOutputStream output) throws
IOException {
MapEntryLite.
writeTo(
output,
metadata,
key,
value);
}
@
Override
public boolean
isInitialized() {
return
isInitialized(
metadata,
value);
}
@
Override
public
Parser<
MapEntry<K, V>>
getParserForType() {
return
metadata.
parser;
}
@
Override
public
Builder<K, V>
newBuilderForType() {
return new
Builder<K, V>(
metadata);
}
@
Override
public
Builder<K, V>
toBuilder() {
return new
Builder<K, V>(
metadata,
key,
value, true, true);
}
@
Override
public
MapEntry<K, V>
getDefaultInstanceForType() {
return new
MapEntry<K, V>(
metadata,
metadata.
defaultKey,
metadata.
defaultValue);
}
@
Override
public
Descriptor getDescriptorForType() {
return
metadata.
descriptor;
}
@
Override
public
Map<
FieldDescriptor,
Object>
getAllFields() {
TreeMap<
FieldDescriptor,
Object>
result = new
TreeMap<
FieldDescriptor,
Object>();
for (final
FieldDescriptor field :
metadata.
descriptor.
getFields()) {
if (
hasField(
field)) {
result.
put(
field,
getField(
field));
}
}
return
Collections.
unmodifiableMap(
result);
}
private void
checkFieldDescriptor(
FieldDescriptor field) {
if (
field.
getContainingType() !=
metadata.
descriptor) {
throw new
RuntimeException(
"Wrong FieldDescriptor \"" +
field.
getFullName()
+ "\" used in message \"" +
metadata.
descriptor.
getFullName());
}
}
@
Override
public boolean
hasField(
FieldDescriptor field) {
checkFieldDescriptor(
field);;
// A MapEntry always contains two fields.
return true;
}
@
Override
public
Object getField(
FieldDescriptor field) {
checkFieldDescriptor(
field);
Object result =
field.
getNumber() == 1 ?
getKey() :
getValue();
// Convert enums to EnumValueDescriptor.
if (
field.
getType() ==
FieldDescriptor.
Type.
ENUM) {
result =
field.
getEnumType().
findValueByNumberCreatingIfUnknown(
(java.lang.
Integer)
result);
}
return
result;
}
@
Override
public int
getRepeatedFieldCount(
FieldDescriptor field) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
Object getRepeatedField(
FieldDescriptor field, int
index) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
UnknownFieldSet getUnknownFields() {
return
UnknownFieldSet.
getDefaultInstance();
}
/**
* Builder to create {@link MapEntry} messages.
*/
public static class
Builder<K, V>
extends
AbstractMessage.
Builder<
Builder<K, V>> {
private final
Metadata<K, V>
metadata;
private K
key;
private V
value;
private boolean
hasKey;
private boolean
hasValue;
private
Builder(
Metadata<K, V>
metadata) {
this(
metadata,
metadata.
defaultKey,
metadata.
defaultValue, false, false);
}
private
Builder(
Metadata<K, V>
metadata, K
key, V
value, boolean
hasKey, boolean
hasValue) {
this.
metadata =
metadata;
this.
key =
key;
this.
value =
value;
this.
hasKey =
hasKey;
this.
hasValue =
hasValue;
}
public K
getKey() {
return
key;
}
public V
getValue() {
return
value;
}
public
Builder<K, V>
setKey(K
key) {
this.
key =
key;
this.
hasKey = true;
return this;
}
public
Builder<K, V>
clearKey() {
this.
key =
metadata.
defaultKey;
this.
hasKey = false;
return this;
}
public
Builder<K, V>
setValue(V
value) {
this.
value =
value;
this.
hasValue = true;
return this;
}
public
Builder<K, V>
clearValue() {
this.
value =
metadata.
defaultValue;
this.
hasValue = false;
return this;
}
@
Override
public
MapEntry<K, V>
build() {
MapEntry<K, V>
result =
buildPartial();
if (!
result.
isInitialized()) {
throw
newUninitializedMessageException(
result);
}
return
result;
}
@
Override
public
MapEntry<K, V>
buildPartial() {
return new
MapEntry<K, V>(
metadata,
key,
value);
}
@
Override
public
Descriptor getDescriptorForType() {
return
metadata.
descriptor;
}
private void
checkFieldDescriptor(
FieldDescriptor field) {
if (
field.
getContainingType() !=
metadata.
descriptor) {
throw new
RuntimeException(
"Wrong FieldDescriptor \"" +
field.
getFullName()
+ "\" used in message \"" +
metadata.
descriptor.
getFullName());
}
}
@
Override
public
Message.
Builder newBuilderForField(
FieldDescriptor field) {
checkFieldDescriptor(
field);;
// This method should be called for message fields and in a MapEntry
// message only the value field can possibly be a message field.
if (
field.
getNumber() != 2
||
field.
getJavaType() !=
FieldDescriptor.
JavaType.
MESSAGE) {
throw new
RuntimeException(
"\"" +
field.
getFullName() + "\" is not a message value field.");
}
return ((
Message)
value).
newBuilderForType();
}
@
SuppressWarnings("unchecked")
@
Override
public
Builder<K, V>
setField(
FieldDescriptor field,
Object value) {
checkFieldDescriptor(
field);
if (
field.
getNumber() == 1) {
setKey((K)
value);
} else {
if (
field.
getType() ==
FieldDescriptor.
Type.
ENUM) {
value = ((
EnumValueDescriptor)
value).
getNumber();
} else if (
field.
getType() ==
FieldDescriptor.
Type.
MESSAGE) {
if (
value != null && !
metadata.
defaultValue.
getClass().
isInstance(
value)) {
// The value is not the exact right message type. However, if it
// is an alternative implementation of the same type -- e.g. a
// DynamicMessage -- we should accept it. In this case we can make
// a copy of the message.
value =
((
Message)
metadata.
defaultValue).
toBuilder().
mergeFrom((
Message)
value).
build();
}
}
setValue((V)
value);
}
return this;
}
@
Override
public
Builder<K, V>
clearField(
FieldDescriptor field) {
checkFieldDescriptor(
field);
if (
field.
getNumber() == 1) {
clearKey();
} else {
clearValue();
}
return this;
}
@
Override
public
Builder<K, V>
setRepeatedField(
FieldDescriptor field, int
index,
Object value) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
Builder<K, V>
addRepeatedField(
FieldDescriptor field,
Object value) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
Builder<K, V>
setUnknownFields(
UnknownFieldSet unknownFields) {
// Unknown fields are discarded for MapEntry message.
return this;
}
@
Override
public
MapEntry<K, V>
getDefaultInstanceForType() {
return new
MapEntry<K, V>(
metadata,
metadata.
defaultKey,
metadata.
defaultValue);
}
@
Override
public boolean
isInitialized() {
return
MapEntry.
isInitialized(
metadata,
value);
}
@
Override
public
Map<
FieldDescriptor,
Object>
getAllFields() {
final
TreeMap<
FieldDescriptor,
Object>
result = new
TreeMap<
FieldDescriptor,
Object>();
for (final
FieldDescriptor field :
metadata.
descriptor.
getFields()) {
if (
hasField(
field)) {
result.
put(
field,
getField(
field));
}
}
return
Collections.
unmodifiableMap(
result);
}
@
Override
public boolean
hasField(
FieldDescriptor field) {
checkFieldDescriptor(
field);
return
field.
getNumber() == 1 ?
hasKey :
hasValue;
}
@
Override
public
Object getField(
FieldDescriptor field) {
checkFieldDescriptor(
field);
Object result =
field.
getNumber() == 1 ?
getKey() :
getValue();
// Convert enums to EnumValueDescriptor.
if (
field.
getType() ==
FieldDescriptor.
Type.
ENUM) {
result =
field.
getEnumType().
findValueByNumberCreatingIfUnknown((
Integer)
result);
}
return
result;
}
@
Override
public int
getRepeatedFieldCount(
FieldDescriptor field) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
Object getRepeatedField(
FieldDescriptor field, int
index) {
throw new
RuntimeException(
"There is no repeated field in a map entry message.");
}
@
Override
public
UnknownFieldSet getUnknownFields() {
return
UnknownFieldSet.
getDefaultInstance();
}
@
Override
@
SuppressWarnings("unchecked")
public
Builder<K, V>
clone() {
return new
Builder(
metadata,
key,
value,
hasKey,
hasValue);
}
}
private static <V> boolean
isInitialized(
Metadata metadata, V
value) {
if (
metadata.
valueType.
getJavaType() ==
WireFormat.
JavaType.
MESSAGE) {
return ((
MessageLite)
value).
isInitialized();
}
return true;
}
/** Returns the metadata only for experimental runtime. */
final
Metadata<K, V>
getMetadata() {
return
metadata;
}
}