parent
baca1a8a1a
commit
6ef984af4b
255 changed files with 25099 additions and 4893 deletions
@ -0,0 +1,63 @@ |
||||
// 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; |
||||
|
||||
/** |
||||
* Lite interface that generated extensions implement. |
||||
* <p> |
||||
* Methods are for use by generated code only. You can hold a reference to |
||||
* extensions using this type name. |
||||
*/ |
||||
public abstract class ExtensionLite<ContainingType extends MessageLite, Type> { |
||||
|
||||
/** Returns the field number of the extension. */ |
||||
public abstract int getNumber(); |
||||
|
||||
/** Returns the type of the field. */ |
||||
public abstract WireFormat.FieldType getLiteType(); |
||||
|
||||
/** Returns whether it is a repeated field. */ |
||||
public abstract boolean isRepeated(); |
||||
|
||||
/** Returns the default value of the extension field. */ |
||||
public abstract Type getDefaultValue(); |
||||
|
||||
/** |
||||
* Returns the default instance of the extension field, if it's a message |
||||
* extension. |
||||
*/ |
||||
public abstract MessageLite getMessageDefaultInstance(); |
||||
|
||||
/** Returns whether or not this extension is a Lite Extension. */ |
||||
boolean isLite() { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,433 @@ |
||||
// 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 class Metadata<K, V> { |
||||
public final Descriptor descriptor; |
||||
public final MapEntry<K, V> defaultInstance; |
||||
public final AbstractParser<MapEntry<K, V>> parser; |
||||
|
||||
public Metadata( |
||||
final Descriptor descriptor, final MapEntry<K, V> defaultInstance) { |
||||
this.descriptor = descriptor; |
||||
this.defaultInstance = defaultInstance; |
||||
final Metadata<K, V> thisMetadata = this; |
||||
this.parser = new AbstractParser<MapEntry<K, V>>() { |
||||
private final Parser<MapEntryLite<K, V>> dataParser = |
||||
defaultInstance.data.getParserForType(); |
||||
@Override |
||||
public MapEntry<K, V> parsePartialFrom( |
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry) |
||||
throws InvalidProtocolBufferException { |
||||
MapEntryLite<K, V> data = |
||||
dataParser.parsePartialFrom(input, extensionRegistry); |
||||
return new MapEntry<K, V>(thisMetadata, data); |
||||
} |
||||
|
||||
}; |
||||
} |
||||
} |
||||
|
||||
private final Metadata<K, V> metadata; |
||||
private final MapEntryLite<K, V> data; |
||||
|
||||
/** Create a default MapEntry instance. */ |
||||
private MapEntry(Descriptor descriptor, |
||||
WireFormat.FieldType keyType, K defaultKey, |
||||
WireFormat.FieldType valueType, V defaultValue) { |
||||
this.data = MapEntryLite.newDefaultInstance( |
||||
keyType, defaultKey, valueType, defaultValue); |
||||
this.metadata = new Metadata<K, V>(descriptor, this); |
||||
} |
||||
|
||||
/** Create a new MapEntry message. */ |
||||
private MapEntry(Metadata<K, V> metadata, MapEntryLite<K, V> data) { |
||||
this.metadata = metadata; |
||||
this.data = data; |
||||
} |
||||
|
||||
/** |
||||
* 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 data.getKey(); |
||||
} |
||||
|
||||
public V getValue() { |
||||
return data.getValue(); |
||||
} |
||||
|
||||
@Override |
||||
public int getSerializedSize() { |
||||
return data.getSerializedSize(); |
||||
} |
||||
|
||||
@Override |
||||
public void writeTo(CodedOutputStream output) throws IOException { |
||||
data.writeTo(output); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
return data.isInitialized(); |
||||
} |
||||
|
||||
@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, data); |
||||
} |
||||
|
||||
@Override |
||||
public MapEntry<K, V> getDefaultInstanceForType() { |
||||
return metadata.defaultInstance; |
||||
} |
||||
|
||||
@Override |
||||
public Descriptor getDescriptorForType() { |
||||
return metadata.descriptor; |
||||
} |
||||
|
||||
@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); |
||||
} |
||||
|
||||
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 MapEntryLite<K, V> data; |
||||
private MapEntryLite.Builder<K, V> dataBuilder; |
||||
|
||||
private Builder(Metadata<K, V> metadata) { |
||||
this.metadata = metadata; |
||||
this.data = metadata.defaultInstance.data; |
||||
this.dataBuilder = null; |
||||
} |
||||
|
||||
private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> data) { |
||||
this.metadata = metadata; |
||||
this.data = data; |
||||
this.dataBuilder = null; |
||||
} |
||||
|
||||
public K getKey() { |
||||
return dataBuilder == null ? data.getKey() : dataBuilder.getKey(); |
||||
} |
||||
|
||||
public V getValue() { |
||||
return dataBuilder == null ? data.getValue() : dataBuilder.getValue(); |
||||
} |
||||
|
||||
private void ensureMutable() { |
||||
if (dataBuilder == null) { |
||||
dataBuilder = data.toBuilder(); |
||||
} |
||||
} |
||||
|
||||
public Builder<K, V> setKey(K key) { |
||||
ensureMutable(); |
||||
dataBuilder.setKey(key); |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> clearKey() { |
||||
ensureMutable(); |
||||
dataBuilder.clearKey(); |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> setValue(V value) { |
||||
ensureMutable(); |
||||
dataBuilder.setValue(value); |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> clearValue() { |
||||
ensureMutable(); |
||||
dataBuilder.clearValue(); |
||||
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() { |
||||
if (dataBuilder != null) { |
||||
data = dataBuilder.build(); |
||||
dataBuilder = null; |
||||
} |
||||
return new MapEntry<K, V>(metadata, data); |
||||
} |
||||
|
||||
@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 com.google.protobuf.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) data.getValue()).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(); |
||||
} |
||||
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 metadata.defaultInstance; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
if (dataBuilder != null) { |
||||
return dataBuilder.isInitialized(); |
||||
} else { |
||||
return data.isInitialized(); |
||||
} |
||||
} |
||||
|
||||
@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 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(); |
||||
} |
||||
|
||||
@Override |
||||
public Builder<K, V> clone() { |
||||
if (dataBuilder == null) { |
||||
return new Builder<K, V>(metadata, data); |
||||
} else { |
||||
return new Builder<K, V>(metadata, dataBuilder.build()); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,331 @@ |
||||
// 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 java.io.IOException; |
||||
|
||||
/** |
||||
* Implements the lite version of map entry messages. |
||||
* |
||||
* This class serves as an utility class to help do serialization/parsing of |
||||
* map entries. It's used in generated code and also in the full version |
||||
* MapEntry message. |
||||
* |
||||
* Protobuf internal. Users shouldn't use. |
||||
*/ |
||||
public class MapEntryLite<K, V> extends AbstractMessageLite { |
||||
private static class Metadata<K, V> { |
||||
public final MapEntryLite<K, V> defaultInstance; |
||||
public final WireFormat.FieldType keyType; |
||||
public final WireFormat.FieldType valueType; |
||||
public final Parser<MapEntryLite<K, V>> parser; |
||||
public Metadata( |
||||
MapEntryLite<K, V> defaultInstance, |
||||
WireFormat.FieldType keyType, |
||||
WireFormat.FieldType valueType) { |
||||
this.defaultInstance = defaultInstance; |
||||
this.keyType = keyType; |
||||
this.valueType = valueType; |
||||
final Metadata<K, V> finalThis = this; |
||||
this.parser = new AbstractParser<MapEntryLite<K, V>>() { |
||||
@Override |
||||
public MapEntryLite<K, V> parsePartialFrom( |
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry) |
||||
throws InvalidProtocolBufferException { |
||||
return new MapEntryLite<K, V>(finalThis, input, extensionRegistry); |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
private static final int KEY_FIELD_NUMBER = 1; |
||||
private static final int VALUE_FIELD_NUMBER = 2; |
||||
|
||||
private final Metadata<K, V> metadata; |
||||
private final K key; |
||||
private final V value; |
||||
|
||||
/** Creates a default MapEntryLite message instance. */ |
||||
private MapEntryLite( |
||||
WireFormat.FieldType keyType, K defaultKey, |
||||
WireFormat.FieldType valueType, V defaultValue) { |
||||
this.metadata = new Metadata<K, V>(this, keyType, valueType); |
||||
this.key = defaultKey; |
||||
this.value = defaultValue; |
||||
} |
||||
|
||||
/** Creates a new MapEntryLite message. */ |
||||
private MapEntryLite(Metadata<K, V> metadata, K key, V value) { |
||||
this.metadata = metadata; |
||||
this.key = key; |
||||
this.value = value; |
||||
} |
||||
|
||||
public K getKey() { |
||||
return key; |
||||
} |
||||
|
||||
public V getValue() { |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* Creates a default MapEntryLite message instance. |
||||
* |
||||
* This method is used by generated code to create the default instance for |
||||
* a map entry message. The created default instance should be used to create |
||||
* new map entry messages of the same type. For each map entry message, only |
||||
* one default instance should be created. |
||||
*/ |
||||
public static <K, V> MapEntryLite<K, V> newDefaultInstance( |
||||
WireFormat.FieldType keyType, K defaultKey, |
||||
WireFormat.FieldType valueType, V defaultValue) { |
||||
return new MapEntryLite<K, V>( |
||||
keyType, defaultKey, valueType, defaultValue); |
||||
} |
||||
|
||||
@Override |
||||
public void writeTo(CodedOutputStream output) throws IOException { |
||||
writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output); |
||||
writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output); |
||||
} |
||||
|
||||
private void writeField( |
||||
int number, WireFormat.FieldType type, Object value, |
||||
CodedOutputStream output) throws IOException { |
||||
output.writeTag(number, type.getWireType()); |
||||
FieldSet.writeElementNoTag(output, type, value); |
||||
} |
||||
|
||||
private volatile int cachedSerializedSize = -1; |
||||
@Override |
||||
public int getSerializedSize() { |
||||
if (cachedSerializedSize != -1) { |
||||
return cachedSerializedSize; |
||||
} |
||||
int size = 0; |
||||
size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key); |
||||
size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value); |
||||
cachedSerializedSize = size; |
||||
return size; |
||||
} |
||||
|
||||
private int getFieldSize( |
||||
int number, WireFormat.FieldType type, Object value) { |
||||
return CodedOutputStream.computeTagSize(number) |
||||
+ FieldSet.computeElementSizeNoTag(type, value); |
||||
} |
||||
|
||||
/** Parsing constructor. */ |
||||
private MapEntryLite( |
||||
Metadata<K, V> metadata, |
||||
CodedInputStream input, |
||||
ExtensionRegistryLite extensionRegistry) |
||||
throws InvalidProtocolBufferException { |
||||
try { |
||||
K key = metadata.defaultInstance.key; |
||||
V value = metadata.defaultInstance.value; |
||||
while (true) { |
||||
int tag = input.readTag(); |
||||
if (tag == 0) { |
||||
break; |
||||
} |
||||
if (tag == WireFormat.makeTag( |
||||
KEY_FIELD_NUMBER, metadata.keyType.getWireType())) { |
||||
key = mergeField( |
||||
input, extensionRegistry, metadata.keyType, key); |
||||
} else if (tag == WireFormat.makeTag( |
||||
VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) { |
||||
value = mergeField( |
||||
input, extensionRegistry, metadata.valueType, value); |
||||
} else { |
||||
if (!input.skipField(tag)) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
this.metadata = metadata; |
||||
this.key = key; |
||||
this.value = value; |
||||
} catch (InvalidProtocolBufferException e) { |
||||
throw e.setUnfinishedMessage(this); |
||||
} catch (IOException e) { |
||||
throw new InvalidProtocolBufferException(e.getMessage()) |
||||
.setUnfinishedMessage(this); |
||||
} |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private <T> T mergeField( |
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry, |
||||
WireFormat.FieldType type, T value) throws IOException { |
||||
switch (type) { |
||||
case MESSAGE: |
||||
MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); |
||||
input.readMessage(subBuilder, extensionRegistry); |
||||
return (T) subBuilder.buildPartial(); |
||||
case ENUM: |
||||
return (T) (java.lang.Integer) input.readEnum(); |
||||
case GROUP: |
||||
throw new RuntimeException("Groups are not allowed in maps."); |
||||
default: |
||||
return (T) FieldSet.readPrimitiveField(input, type, true); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Parser<MapEntryLite<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); |
||||
} |
||||
|
||||
@Override |
||||
public MapEntryLite<K, V> getDefaultInstanceForType() { |
||||
return metadata.defaultInstance; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { |
||||
return ((MessageLite) value).isInitialized(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Builder used to create {@link MapEntryLite} messages. |
||||
*/ |
||||
public static class Builder<K, V> |
||||
extends AbstractMessageLite.Builder<Builder<K, V>> { |
||||
private final Metadata<K, V> metadata; |
||||
private K key; |
||||
private V value; |
||||
|
||||
private Builder(Metadata<K, V> metadata) { |
||||
this.metadata = metadata; |
||||
this.key = metadata.defaultInstance.key; |
||||
this.value = metadata.defaultInstance.value; |
||||
} |
||||
|
||||
public K getKey() { |
||||
return key; |
||||
} |
||||
|
||||
public V getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public Builder<K, V> setKey(K key) { |
||||
this.key = key; |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> setValue(V value) { |
||||
this.value = value; |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> clearKey() { |
||||
this.key = metadata.defaultInstance.key; |
||||
return this; |
||||
} |
||||
|
||||
public Builder<K, V> clearValue() { |
||||
this.value = metadata.defaultInstance.value; |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public Builder<K, V> clear() { |
||||
this.key = metadata.defaultInstance.key; |
||||
this.value = metadata.defaultInstance.value; |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public MapEntryLite<K, V> build() { |
||||
MapEntryLite<K, V> result = buildPartial(); |
||||
if (!result.isInitialized()) { |
||||
throw newUninitializedMessageException(result); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public MapEntryLite<K, V> buildPartial() { |
||||
return new MapEntryLite<K, V>(metadata, key, value); |
||||
} |
||||
|
||||
@Override |
||||
public MessageLite getDefaultInstanceForType() { |
||||
return metadata.defaultInstance; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { |
||||
return ((MessageLite) value).isInitialized(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private Builder(Metadata<K, V> metadata, K key, V value) { |
||||
this.metadata = metadata; |
||||
this.key = key; |
||||
this.value = value; |
||||
} |
||||
|
||||
@Override |
||||
public Builder<K, V> clone() { |
||||
return new Builder<K, V>(metadata, key, value); |
||||
} |
||||
|
||||
@Override |
||||
public Builder<K, V> mergeFrom( |
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry) |
||||
throws IOException { |
||||
MapEntryLite<K, V> entry = |
||||
new MapEntryLite<K, V>(metadata, input, extensionRegistry); |
||||
this.key = entry.key; |
||||
this.value = entry.value; |
||||
return this; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,259 @@ |
||||
// 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 java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Internal representation of map fields in generated messages. |
||||
* |
||||
* This class supports accessing the map field as a {@link Map} to be used in |
||||
* generated API and also supports accessing the field as a {@link List} to be |
||||
* used in reflection API. It keeps track of where the data is currently stored |
||||
* and do necessary conversions between map and list. |
||||
* |
||||
* This class is a protobuf implementation detail. Users shouldn't use this |
||||
* class directly. |
||||
* |
||||
* THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap() |
||||
* and getList() concurrently in multiple threads. If write-access is needed, |
||||
* all access must be synchronized. |
||||
*/ |
||||
public class MapField<K, V> { |
||||
/** |
||||
* Indicates where the data of this map field is currently stored. |
||||
* |
||||
* MAP: Data is stored in mapData. |
||||
* LIST: Data is stored in listData. |
||||
* BOTH: mapData and listData have the same data. |
||||
* |
||||
* When the map field is accessed (through generated API or reflection API), |
||||
* it will shift between these 3 modes: |
||||
* |
||||
* getMap() getList() getMutableMap() getMutableList() |
||||
* MAP MAP BOTH MAP LIST |
||||
* LIST BOTH LIST MAP LIST |
||||
* BOTH BOTH BOTH MAP LIST |
||||
* |
||||
* As the map field changes its mode, the list/map reference returned in a |
||||
* previous method call may be invalidated. |
||||
*/ |
||||
private enum StorageMode {MAP, LIST, BOTH} |
||||
|
||||
private volatile StorageMode mode; |
||||
private Map<K, V> mapData; |
||||
private List<Message> listData; |
||||
|
||||
// Convert between a map entry Message and a key-value pair.
|
||||
private static interface Converter<K, V> { |
||||
Message convertKeyAndValueToMessage(K key, V value); |
||||
void convertMessageToKeyAndValue(Message message, Map<K, V> map); |
||||
|
||||
Message getMessageDefaultInstance(); |
||||
} |
||||
|
||||
private static class ImmutableMessageConverter<K, V> implements Converter<K, V> { |
||||
private final MapEntry<K, V> defaultEntry; |
||||
public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) { |
||||
this.defaultEntry = defaultEntry; |
||||
} |
||||
|
||||
public Message convertKeyAndValueToMessage(K key, V value) { |
||||
return defaultEntry.newBuilderForType().setKey(key).setValue(value).build(); |
||||
} |
||||
|
||||
public void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
||||
MapEntry<K, V> entry = (MapEntry<K, V>) message; |
||||
map.put(entry.getKey(), entry.getValue()); |
||||
} |
||||
|
||||
public Message getMessageDefaultInstance() { |
||||
return defaultEntry; |
||||
} |
||||
} |
||||
|
||||
|
||||
private final Converter<K, V> converter; |
||||
|
||||
private MapField( |
||||
Converter<K, V> converter, |
||||
StorageMode mode, |
||||
Map<K, V> mapData, |
||||
List<Message> listData) { |
||||
this.converter = converter; |
||||
this.mode = mode; |
||||
this.mapData = mapData; |
||||
this.listData = listData; |
||||
} |
||||
|
||||
private MapField( |
||||
MapEntry<K, V> defaultEntry, |
||||
StorageMode mode, |
||||
Map<K, V> mapData, |
||||
List<Message> listData) { |
||||
this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData, listData); |
||||
} |
||||
|
||||
|
||||
/** Returns an immutable empty MapField. */ |
||||
public static <K, V> MapField<K, V> emptyMapField( |
||||
MapEntry<K, V> defaultEntry) { |
||||
return new MapField<K, V>( |
||||
defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap(), null); |
||||
} |
||||
|
||||
|
||||
/** Creates a new mutable empty MapField. */ |
||||
public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) { |
||||
return new MapField<K, V>( |
||||
defaultEntry, StorageMode.MAP, new HashMap<K, V>(), null); |
||||
} |
||||
|
||||
|
||||
private Message convertKeyAndValueToMessage(K key, V value) { |
||||
return converter.convertKeyAndValueToMessage(key, value); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private void convertMessageToKeyAndValue(Message message, Map<K, V> map) { |
||||
converter.convertMessageToKeyAndValue(message, map); |
||||
} |
||||
|
||||
private List<Message> convertMapToList(Map<K, V> mapData) { |
||||
List<Message> listData = new ArrayList<Message>(); |
||||
for (Map.Entry<K, V> entry : mapData.entrySet()) { |
||||
listData.add( |
||||
convertKeyAndValueToMessage( |
||||
entry.getKey(), entry.getValue())); |
||||
} |
||||
return listData; |
||||
} |
||||
|
||||
private Map<K, V> convertListToMap(List<Message> listData) { |
||||
Map<K, V> mapData = new HashMap<K, V>(); |
||||
for (Message item : listData) { |
||||
convertMessageToKeyAndValue(item, mapData); |
||||
} |
||||
return mapData; |
||||
} |
||||
|
||||
/** Returns the content of this MapField as a read-only Map. */ |
||||
public Map<K, V> getMap() { |
||||
if (mode == StorageMode.LIST) { |
||||
synchronized (this) { |
||||
if (mode == StorageMode.LIST) { |
||||
mapData = convertListToMap(listData); |
||||
mode = StorageMode.BOTH; |
||||
} |
||||
} |
||||
} |
||||
return Collections.unmodifiableMap(mapData); |
||||
} |
||||
|
||||
/** Gets a mutable Map view of this MapField. */ |
||||
public Map<K, V> getMutableMap() { |
||||
if (mode != StorageMode.MAP) { |
||||
if (mode == StorageMode.LIST) { |
||||
mapData = convertListToMap(listData); |
||||
} |
||||
listData = null; |
||||
mode = StorageMode.MAP; |
||||
} |
||||
return mapData; |
||||
} |
||||
|
||||
public void mergeFrom(MapField<K, V> other) { |
||||
getMutableMap().putAll(MapFieldLite.copy(other.getMap())); |
||||
} |
||||
|
||||
public void clear() { |
||||
mapData = new HashMap<K, V>(); |
||||
mode = StorageMode.MAP; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public boolean equals(Object object) { |
||||
if (!(object instanceof MapField)) { |
||||
return false; |
||||
} |
||||
MapField<K, V> other = (MapField<K, V>) object; |
||||
return MapFieldLite.<K, V>equals(getMap(), other.getMap()); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return MapFieldLite.<K, V>calculateHashCodeForMap(getMap()); |
||||
} |
||||
|
||||
/** Returns a deep copy of this MapField. */ |
||||
public MapField<K, V> copy() { |
||||
return new MapField<K, V>( |
||||
converter, StorageMode.MAP, MapFieldLite.copy(getMap()), null); |
||||
} |
||||
|
||||
/** Gets the content of this MapField as a read-only List. */ |
||||
List<Message> getList() { |
||||
if (mode == StorageMode.MAP) { |
||||
synchronized (this) { |
||||
if (mode == StorageMode.MAP) { |
||||
listData = convertMapToList(mapData); |
||||
mode = StorageMode.BOTH; |
||||
} |
||||
} |
||||
} |
||||
return Collections.unmodifiableList(listData); |
||||
} |
||||
|
||||
/** Gets a mutable List view of this MapField. */ |
||||
List<Message> getMutableList() { |
||||
if (mode != StorageMode.LIST) { |
||||
if (mode == StorageMode.MAP) { |
||||
listData = convertMapToList(mapData); |
||||
} |
||||
mapData = null; |
||||
mode = StorageMode.LIST; |
||||
} |
||||
return listData; |
||||
} |
||||
|
||||
/** |
||||
* Gets the default instance of the message stored in the list view of this |
||||
* map field. |
||||
*/ |
||||
Message getMapEntryMessageDefaultInstance() { |
||||
return converter.getMessageDefaultInstance(); |
||||
} |
||||
} |
@ -0,0 +1,182 @@ |
||||
// 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 java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Internal representation of map fields in generated lite-runtime messages. |
||||
* |
||||
* This class is a protobuf implementation detail. Users shouldn't use this |
||||
* class directly. |
||||
*/ |
||||
public class MapFieldLite<K, V> { |
||||
private Map<K, V> mapData; |
||||
|
||||
private MapFieldLite(Map<K, V> mapData) { |
||||
this.mapData = mapData; |
||||
} |
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"}) |
||||
private static final MapFieldLite EMPTY_MAP_FIELD = |
||||
new MapFieldLite(Collections.emptyMap()); |
||||
|
||||
/** Returns an singleton immutable empty MapFieldLite instance. */ |
||||
@SuppressWarnings({"unchecked", "cast"}) |
||||
public static <K, V> MapFieldLite<K, V> emptyMapField() { |
||||
return (MapFieldLite<K, V>) EMPTY_MAP_FIELD; |
||||
} |
||||
|
||||
/** Creates a new MapFieldLite instance. */ |
||||
public static <K, V> MapFieldLite<K, V> newMapField() { |
||||
return new MapFieldLite<K, V>(new HashMap<K, V>()); |
||||
} |
||||
|
||||
/** Gets the content of this MapField as a read-only Map. */ |
||||
public Map<K, V> getMap() { |
||||
return Collections.unmodifiableMap(mapData); |
||||
} |
||||
|
||||
/** Gets a mutable Map view of this MapField. */ |
||||
public Map<K, V> getMutableMap() { |
||||
return mapData; |
||||
} |
||||
|
||||
public void mergeFrom(MapFieldLite<K, V> other) { |
||||
mapData.putAll(copy(other.mapData)); |
||||
} |
||||
|
||||
public void clear() { |
||||
mapData.clear(); |
||||
} |
||||
|
||||
private static boolean equals(Object a, Object b) { |
||||
if (a instanceof byte[] && b instanceof byte[]) { |
||||
return Arrays.equals((byte[]) a, (byte[]) b); |
||||
} |
||||
return a.equals(b); |
||||
} |
||||
|
||||
/** |
||||
* Checks whether two {@link Map}s are equal. We don't use the default equals |
||||
* method of {@link Map} because it compares by identity not by content for |
||||
* byte arrays. |
||||
*/ |
||||
static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) { |
||||
if (a == b) { |
||||
return true; |
||||
} |
||||
if (a.size() != a.size()) { |
||||
return false; |
||||
} |
||||
for (Map.Entry<K, V> entry : a.entrySet()) { |
||||
if (!b.containsKey(entry.getKey())) { |
||||
return false; |
||||
} |
||||
if (!equals(entry.getValue(), b.get(entry.getKey()))) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether two map fields are equal. |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public boolean equals(Object object) { |
||||
if (!(object instanceof MapFieldLite)) { |
||||
return false; |
||||
} |
||||
MapFieldLite<K, V> other = (MapFieldLite<K, V>) object; |
||||
return equals(mapData, other.mapData); |
||||
} |
||||
|
||||
private static int calculateHashCodeForObject(Object a) { |
||||
if (a instanceof byte[]) { |
||||
return LiteralByteString.hashCode((byte[]) a); |
||||
} |
||||
if (a instanceof Internal.EnumLite) { |
||||
return Internal.hashEnum((Internal.EnumLite) a); |
||||
} |
||||
return a.hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* Calculates the hash code for a {@link Map}. We don't use the default hash |
||||
* code method of {@link Map} because for byte arrays and protobuf enums it |
||||
* use {@link Object#hashCode()}. |
||||
*/ |
||||
static <K, V> int calculateHashCodeForMap(Map<K, V> a) { |
||||
int result = 0; |
||||
for (Map.Entry<K, V> entry : a.entrySet()) { |
||||
result += calculateHashCodeForObject(entry.getKey()) |
||||
^ calculateHashCodeForObject(entry.getValue()); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return calculateHashCodeForMap(mapData); |
||||
} |
||||
|
||||
private static Object copy(Object object) { |
||||
if (object instanceof byte[]) { |
||||
byte[] data = (byte[]) object; |
||||
return Arrays.copyOf(data, data.length); |
||||
} |
||||
return object; |
||||
} |
||||
|
||||
/** |
||||
* Makes a deep copy of a {@link Map}. Immutable objects in the map will be |
||||
* shared (e.g., integers, strings, immutable messages) and mutable ones will |
||||
* have a copy (e.g., byte arrays, mutable messages). |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
static <K, V> Map<K, V> copy(Map<K, V> map) { |
||||
Map<K, V> result = new HashMap<K, V>(); |
||||
for (Map.Entry<K, V> entry : map.entrySet()) { |
||||
result.put(entry.getKey(), (V) copy(entry.getValue())); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** Returns a deep copy of this map field. */ |
||||
public MapFieldLite<K, V> copy() { |
||||
return new MapFieldLite<K, V>(copy(mapData)); |
||||
} |
||||
} |
@ -0,0 +1,297 @@ |
||||
// 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 java.io.IOException; |
||||
|
||||
/** |
||||
* {@code UnknownFieldSetLite} is used to keep track of fields which were seen |
||||
* when parsing a protocol message but whose field numbers or types are |
||||
* unrecognized. This most frequently occurs when new fields are added to a |
||||
* message type and then messages containing those fields are read by old |
||||
* software that was compiled before the new types were added. |
||||
* |
||||
* <p>For use by generated code only. |
||||
* |
||||
* @author dweis@google.com (Daniel Weis) |
||||
*/ |
||||
public final class UnknownFieldSetLite { |
||||
|
||||
private static final UnknownFieldSetLite DEFAULT_INSTANCE = |
||||
new UnknownFieldSetLite(ByteString.EMPTY); |
||||
|
||||
/** |
||||
* Get an empty {@code UnknownFieldSetLite}. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public static UnknownFieldSetLite getDefaultInstance() { |
||||
return DEFAULT_INSTANCE; |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link Builder}. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public static Builder newBuilder() { |
||||
return new Builder(); |
||||
} |
||||
|
||||
/** |
||||
* Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and |
||||
* {@code second}. |
||||
*/ |
||||
static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) { |
||||
return new UnknownFieldSetLite(first.byteString.concat(second.byteString)); |
||||
} |
||||
|
||||
/** |
||||
* The internal representation of the unknown fields. |
||||
*/ |
||||
private final ByteString byteString; |
||||
|
||||
/** |
||||
* Constructs the {@code UnknownFieldSetLite} as a thin wrapper around {@link ByteString}. |
||||
*/ |
||||
private UnknownFieldSetLite(ByteString byteString) { |
||||
this.byteString = byteString; |
||||
} |
||||
|
||||
/** |
||||
* Serializes the set and writes it to {@code output}. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public void writeTo(CodedOutputStream output) throws IOException { |
||||
output.writeRawBytes(byteString); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the number of bytes required to encode this set. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public int getSerializedSize() { |
||||
return byteString.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (this == obj) { |
||||
return true; |
||||
} |
||||
|
||||
if (obj instanceof UnknownFieldSetLite) { |
||||
return byteString.equals(((UnknownFieldSetLite) obj).byteString); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return byteString.hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* Builder for {@link UnknownFieldSetLite}s. |
||||
* |
||||
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public static final class Builder { |
||||
|
||||
private ByteString.Output byteStringOutput; |
||||
private CodedOutputStream output; |
||||
private boolean built; |
||||
|
||||
/** |
||||
* Constructs a {@code Builder}. Lazily initialized by |
||||
* {@link #ensureInitializedButNotBuilt()}. |
||||
*/ |
||||
private Builder() {} |
||||
|
||||
/** |
||||
* Ensures internal state is initialized for use. |
||||
*/ |
||||
private void ensureInitializedButNotBuilt() { |
||||
if (built) { |
||||
throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); |
||||
} |
||||
|
||||
if (output == null && byteStringOutput == null) { |
||||
byteStringOutput = ByteString.newOutput(100 /* initialCapacity */); |
||||
output = CodedOutputStream.newInstance(byteStringOutput); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parse a single field from {@code input} and merge it into this set. |
||||
* |
||||
* <p>For use by generated code only. |
||||
* |
||||
* @param tag The field's tag number, which was already parsed. |
||||
* @return {@code false} if the tag is an end group tag. |
||||
*/ |
||||
public boolean mergeFieldFrom(final int tag, final CodedInputStream input) |
||||
throws IOException { |
||||
ensureInitializedButNotBuilt(); |
||||
|
||||
final int fieldNumber = WireFormat.getTagFieldNumber(tag); |
||||
switch (WireFormat.getTagWireType(tag)) { |
||||
case WireFormat.WIRETYPE_VARINT: |
||||
output.writeUInt64(fieldNumber, input.readInt64()); |
||||
return true; |
||||
case WireFormat.WIRETYPE_FIXED32: |
||||
output.writeFixed32(fieldNumber, input.readFixed32()); |
||||
return true; |
||||
case WireFormat.WIRETYPE_FIXED64: |
||||
output.writeFixed64(fieldNumber, input.readFixed64()); |
||||
return true; |
||||
case WireFormat.WIRETYPE_LENGTH_DELIMITED: |
||||
output.writeBytes(fieldNumber, input.readBytes()); |
||||
return true; |
||||
case WireFormat.WIRETYPE_START_GROUP: |
||||
final Builder subBuilder = newBuilder(); |
||||
subBuilder.mergeFrom(input); |
||||
input.checkLastTagWas( |
||||
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); |
||||
|
||||
output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); |
||||
subBuilder.build().writeTo(output); |
||||
output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); |
||||
return true; |
||||
case WireFormat.WIRETYPE_END_GROUP: |
||||
return false; |
||||
default: |
||||
throw InvalidProtocolBufferException.invalidWireType(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Convenience method for merging a new field containing a single varint |
||||
* value. This is used in particular when an unknown enum value is |
||||
* encountered. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public Builder mergeVarintField(int fieldNumber, int value) { |
||||
if (fieldNumber == 0) { |
||||
throw new IllegalArgumentException("Zero is not a valid field number."); |
||||
} |
||||
ensureInitializedButNotBuilt(); |
||||
try { |
||||
output.writeUInt64(fieldNumber, value); |
||||
} catch (IOException e) { |
||||
// Should never happen.
|
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Convenience method for merging a length-delimited field. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public Builder mergeLengthDelimitedField( |
||||
final int fieldNumber, final ByteString value) { |
||||
if (fieldNumber == 0) { |
||||
throw new IllegalArgumentException("Zero is not a valid field number."); |
||||
} |
||||
ensureInitializedButNotBuilt(); |
||||
try { |
||||
output.writeBytes(fieldNumber, value); |
||||
} catch (IOException e) { |
||||
// Should never happen.
|
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Build the {@link UnknownFieldSetLite} and return it. |
||||
* |
||||
* <p>Once {@code build()} has been called, the {@code Builder} will no |
||||
* longer be usable. Calling any method after {@code build()} will result |
||||
* in undefined behavior and can cause a {@code IllegalStateException} to be |
||||
* thrown. |
||||
* |
||||
* <p>For use by generated code only. |
||||
*/ |
||||
public UnknownFieldSetLite build() { |
||||
if (built) { |
||||
throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); |
||||
} |
||||
|
||||
built = true; |
||||
|
||||
final UnknownFieldSetLite result; |
||||
// If we were never initialized, no data was written.
|
||||
if (output == null) { |
||||
result = getDefaultInstance(); |
||||
} else { |
||||
try { |
||||
output.flush(); |
||||
} catch (IOException e) { |
||||
// Should never happen.
|
||||
} |
||||
ByteString byteString = byteStringOutput.toByteString(); |
||||
if (byteString.isEmpty()) { |
||||
result = getDefaultInstance(); |
||||
} else { |
||||
result = new UnknownFieldSetLite(byteString); |
||||
} |
||||
} |
||||
|
||||
// Allow for garbage collection.
|
||||
output = null; |
||||
byteStringOutput = null; |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Parse an entire message from {@code input} and merge its fields into |
||||
* this set. |
||||
*/ |
||||
private Builder mergeFrom(final CodedInputStream input) throws IOException { |
||||
// Ensures initialization in mergeFieldFrom.
|
||||
while (true) { |
||||
final int tag = input.readTag(); |
||||
if (tag == 0 || !mergeFieldFrom(tag, input)) { |
||||
break; |
||||
} |
||||
} |
||||
return this; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,363 @@ |
||||
// 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.FieldDescriptor; |
||||
import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; |
||||
import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly; |
||||
import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly; |
||||
import protobuf_unittest.UnittestProto; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Unit tests for protos that doesn't support field presence test for optional |
||||
* non-message fields. |
||||
*/ |
||||
public class FieldPresenceTest extends TestCase { |
||||
private static boolean hasMethod(Class clazz, String name) { |
||||
try { |
||||
if (clazz.getMethod(name, new Class[]{}) != null) { |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} catch (NoSuchMethodException e) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static boolean isHasMethodRemoved( |
||||
Class classWithFieldPresence, |
||||
Class classWithoutFieldPresence, |
||||
String camelName) { |
||||
return hasMethod(classWithFieldPresence, "get" + camelName) |
||||
&& hasMethod(classWithFieldPresence, "has" + camelName) |
||||
&& hasMethod(classWithoutFieldPresence, "get" + camelName) |
||||
&& !hasMethod(classWithoutFieldPresence, "has" + camelName); |
||||
} |
||||
|
||||
public void testHasMethod() { |
||||
// Optional non-message fields don't have a hasFoo() method generated.
|
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OptionalInt32")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OptionalString")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OptionalBytes")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OptionalNestedEnum")); |
||||
|
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OptionalInt32")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OptionalString")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OptionalBytes")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OptionalNestedEnum")); |
||||
|
||||
// message fields still have the hasFoo() method generated.
|
||||
assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage()); |
||||
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage()); |
||||
|
||||
// oneof fields don't have hasFoo() methods (even for message types).
|
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OneofUint32")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OneofString")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OneofBytes")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.class, |
||||
TestAllTypes.class, |
||||
"OneofNestedMessage")); |
||||
|
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OneofUint32")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OneofString")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OneofBytes")); |
||||
assertTrue(isHasMethodRemoved( |
||||
UnittestProto.TestAllTypes.Builder.class, |
||||
TestAllTypes.Builder.class, |
||||
"OneofNestedMessage")); |
||||
} |
||||
|
||||
public void testFieldPresence() { |
||||
// Optional non-message fields set to their default value are treated the
|
||||
// same way as not set.
|
||||
|
||||
// Serialization will ignore such fields.
|
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalInt32(0); |
||||
builder.setOptionalString(""); |
||||
builder.setOptionalBytes(ByteString.EMPTY); |
||||
builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO); |
||||
TestAllTypes message = builder.build(); |
||||
assertEquals(0, message.getSerializedSize()); |
||||
|
||||
// mergeFrom() will ignore such fields.
|
||||
TestAllTypes.Builder a = TestAllTypes.newBuilder(); |
||||
a.setOptionalInt32(1); |
||||
a.setOptionalString("x"); |
||||
a.setOptionalBytes(ByteString.copyFromUtf8("y")); |
||||
a.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR); |
||||
TestAllTypes.Builder b = TestAllTypes.newBuilder(); |
||||
b.setOptionalInt32(0); |
||||
b.setOptionalString(""); |
||||
b.setOptionalBytes(ByteString.EMPTY); |
||||
b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO); |
||||
a.mergeFrom(b.build()); |
||||
message = a.build(); |
||||
assertEquals(1, message.getOptionalInt32()); |
||||
assertEquals("x", message.getOptionalString()); |
||||
assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes()); |
||||
assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); |
||||
|
||||
// equals()/hashCode() should produce the same results.
|
||||
TestAllTypes empty = TestAllTypes.newBuilder().build(); |
||||
message = builder.build(); |
||||
assertTrue(empty.equals(message)); |
||||
assertTrue(message.equals(empty)); |
||||
assertEquals(empty.hashCode(), message.hashCode()); |
||||
} |
||||
|
||||
public void testFieldPresenceByReflection() { |
||||
Descriptor descriptor = TestAllTypes.getDescriptor(); |
||||
FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32"); |
||||
FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string"); |
||||
FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes"); |
||||
FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); |
||||
|
||||
// Field not present.
|
||||
TestAllTypes message = TestAllTypes.newBuilder().build(); |
||||
assertFalse(message.hasField(optionalInt32Field)); |
||||
assertFalse(message.hasField(optionalStringField)); |
||||
assertFalse(message.hasField(optionalBytesField)); |
||||
assertFalse(message.hasField(optionalNestedEnumField)); |
||||
assertEquals(0, message.getAllFields().size()); |
||||
|
||||
// Field set to default value is seen as not present.
|
||||
message = TestAllTypes.newBuilder() |
||||
.setOptionalInt32(0) |
||||
.setOptionalString("") |
||||
.setOptionalBytes(ByteString.EMPTY) |
||||
.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO) |
||||
.build(); |
||||
assertFalse(message.hasField(optionalInt32Field)); |
||||
assertFalse(message.hasField(optionalStringField)); |
||||
assertFalse(message.hasField(optionalBytesField)); |
||||
assertFalse(message.hasField(optionalNestedEnumField)); |
||||
assertEquals(0, message.getAllFields().size()); |
||||
|
||||
// Field set to non-default value is seen as present.
|
||||
message = TestAllTypes.newBuilder() |
||||
.setOptionalInt32(1) |
||||
.setOptionalString("x") |
||||
.setOptionalBytes(ByteString.copyFromUtf8("y")) |
||||
.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR) |
||||
.build(); |
||||
assertTrue(message.hasField(optionalInt32Field)); |
||||
assertTrue(message.hasField(optionalStringField)); |
||||
assertTrue(message.hasField(optionalBytesField)); |
||||
assertTrue(message.hasField(optionalNestedEnumField)); |
||||
assertEquals(4, message.getAllFields().size()); |
||||
} |
||||
|
||||
public void testMessageField() { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
assertFalse(builder.hasOptionalNestedMessage()); |
||||
assertFalse(builder.build().hasOptionalNestedMessage()); |
||||
|
||||
TestAllTypes.NestedMessage.Builder nestedBuilder = |
||||
builder.getOptionalNestedMessageBuilder(); |
||||
assertTrue(builder.hasOptionalNestedMessage()); |
||||
assertTrue(builder.build().hasOptionalNestedMessage()); |
||||
|
||||
nestedBuilder.setValue(1); |
||||
assertEquals(1, builder.build().getOptionalNestedMessage().getValue()); |
||||
|
||||
builder.clearOptionalNestedMessage(); |
||||
assertFalse(builder.hasOptionalNestedMessage()); |
||||
assertFalse(builder.build().hasOptionalNestedMessage()); |
||||
|
||||
// Unlike non-message fields, if we set a message field to its default value (i.e.,
|
||||
// default instance), the field should be seen as present.
|
||||
builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); |
||||
assertTrue(builder.hasOptionalNestedMessage()); |
||||
assertTrue(builder.build().hasOptionalNestedMessage()); |
||||
} |
||||
|
||||
public void testSerializeAndParse() throws Exception { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalInt32(1234); |
||||
builder.setOptionalString("hello"); |
||||
builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); |
||||
// Set an oneof field to its default value and expect it to be serialized (i.e.,
|
||||
// an oneof field set to the default value should be treated as present).
|
||||
builder.setOneofInt32(0); |
||||
ByteString data = builder.build().toByteString(); |
||||
|
||||
TestAllTypes message = TestAllTypes.parseFrom(data); |
||||
assertEquals(1234, message.getOptionalInt32()); |
||||
assertEquals("hello", message.getOptionalString()); |
||||
// Fields not set will have the default value.
|
||||
assertEquals(ByteString.EMPTY, message.getOptionalBytes()); |
||||
assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum()); |
||||
// The message field is set despite that it's set with a default instance.
|
||||
assertTrue(message.hasOptionalNestedMessage()); |
||||
assertEquals(0, message.getOptionalNestedMessage().getValue()); |
||||
// The oneof field set to its default value is also present.
|
||||
assertEquals( |
||||
TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase()); |
||||
} |
||||
|
||||
// Regression test for b/16173397
|
||||
// Make sure we haven't screwed up the code generation for repeated fields.
|
||||
public void testRepeatedFields() throws Exception { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalInt32(1234); |
||||
builder.setOptionalString("hello"); |
||||
builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); |
||||
builder.addRepeatedInt32(4321); |
||||
builder.addRepeatedString("world"); |
||||
builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); |
||||
ByteString data = builder.build().toByteString(); |
||||
|
||||
TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data); |
||||
assertEquals(1234, optionalOnlyMessage.getOptionalInt32()); |
||||
assertEquals("hello", optionalOnlyMessage.getOptionalString()); |
||||
assertTrue(optionalOnlyMessage.hasOptionalNestedMessage()); |
||||
assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue()); |
||||
|
||||
TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data); |
||||
assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count()); |
||||
assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0)); |
||||
assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount()); |
||||
assertEquals("world", repeatedOnlyMessage.getRepeatedString(0)); |
||||
assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount()); |
||||
assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue()); |
||||
} |
||||
|
||||
public void testIsInitialized() throws Exception { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
|
||||
// Test optional proto2 message fields.
|
||||
UnittestProto.TestRequired.Builder proto2Builder = |
||||
builder.getOptionalProto2MessageBuilder(); |
||||
assertFalse(builder.isInitialized()); |
||||
assertFalse(builder.buildPartial().isInitialized()); |
||||
|
||||
proto2Builder.setA(1).setB(2).setC(3); |
||||
assertTrue(builder.isInitialized()); |
||||
assertTrue(builder.buildPartial().isInitialized()); |
||||
|
||||
// Test oneof proto2 message fields.
|
||||
proto2Builder = builder.getOneofProto2MessageBuilder(); |
||||
assertFalse(builder.isInitialized()); |
||||
assertFalse(builder.buildPartial().isInitialized()); |
||||
|
||||
proto2Builder.setA(1).setB(2).setC(3); |
||||
assertTrue(builder.isInitialized()); |
||||
assertTrue(builder.buildPartial().isInitialized()); |
||||
|
||||
// Test repeated proto2 message fields.
|
||||
proto2Builder = builder.addRepeatedProto2MessageBuilder(); |
||||
assertFalse(builder.isInitialized()); |
||||
assertFalse(builder.buildPartial().isInitialized()); |
||||
|
||||
proto2Builder.setA(1).setB(2).setC(3); |
||||
assertTrue(builder.isInitialized()); |
||||
assertTrue(builder.buildPartial().isInitialized()); |
||||
} |
||||
|
||||
|
||||
// Test that unknown fields are dropped.
|
||||
public void testUnknownFields() throws Exception { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalInt32(1234); |
||||
builder.addRepeatedInt32(5678); |
||||
TestAllTypes message = builder.build(); |
||||
ByteString data = message.toByteString(); |
||||
|
||||
TestOptionalFieldsOnly optionalOnlyMessage = |
||||
TestOptionalFieldsOnly.parseFrom(data); |
||||
// UnknownFieldSet should be empty.
|
||||
assertEquals( |
||||
0, optionalOnlyMessage.getUnknownFields().toByteString().size()); |
||||
assertEquals(1234, optionalOnlyMessage.getOptionalInt32()); |
||||
message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString()); |
||||
assertEquals(1234, message.getOptionalInt32()); |
||||
// The repeated field is discarded because it's unknown to the optional-only
|
||||
// message.
|
||||
assertEquals(0, message.getRepeatedInt32Count()); |
||||
|
||||
DynamicMessage dynamicOptionalOnlyMessage = |
||||
DynamicMessage.getDefaultInstance( |
||||
TestOptionalFieldsOnly.getDescriptor()) |
||||
.getParserForType().parseFrom(data); |
||||
assertEquals( |
||||
0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size()); |
||||
assertEquals(optionalOnlyMessage.toByteString(), |
||||
dynamicOptionalOnlyMessage.toByteString()); |
||||
} |
||||
} |
@ -0,0 +1,277 @@ |
||||
// 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 map_lite_test.MapForProto2TestProto.TestMap; |
||||
import map_lite_test.MapForProto2TestProto.TestMap.MessageValue; |
||||
import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Unit tests for map fields. |
||||
*/ |
||||
public class MapForProto2LiteTest extends TestCase { |
||||
private void setMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 11); |
||||
builder.getMutableInt32ToInt32Field().put(2, 22); |
||||
builder.getMutableInt32ToInt32Field().put(3, 33); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "11"); |
||||
builder.getMutableInt32ToStringField().put(2, "22"); |
||||
builder.getMutableInt32ToStringField().put(3, "33"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); |
||||
builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); |
||||
builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); |
||||
builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(11).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
2, MessageValue.newBuilder().setValue(22).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
3, MessageValue.newBuilder().setValue(33).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 11); |
||||
builder.getMutableStringToInt32Field().put("2", 22); |
||||
builder.getMutableStringToInt32Field().put("3", 33); |
||||
} |
||||
|
||||
private void assertMapValuesSet(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("11", message.getInt32ToStringField().get(1)); |
||||
assertEquals("22", message.getInt32ToStringField().get(2)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(11, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(22, message.getStringToInt32Field().get("2").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
} |
||||
|
||||
private void updateMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 111); |
||||
builder.getMutableInt32ToInt32Field().remove(2); |
||||
builder.getMutableInt32ToInt32Field().put(4, 44); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "111"); |
||||
builder.getMutableInt32ToStringField().remove(2); |
||||
builder.getMutableInt32ToStringField().put(4, "44"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); |
||||
builder.getMutableInt32ToBytesField().remove(2); |
||||
builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().remove(2); |
||||
builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(111).build()); |
||||
builder.getMutableInt32ToMessageField().remove(2); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
4, MessageValue.newBuilder().setValue(44).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 111); |
||||
builder.getMutableStringToInt32Field().remove("2"); |
||||
builder.getMutableStringToInt32Field().put("4", 44); |
||||
} |
||||
|
||||
private void assertMapValuesUpdated(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("111", message.getInt32ToStringField().get(1)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
assertEquals("44", message.getInt32ToStringField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(111, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
assertEquals(44, message.getStringToInt32Field().get("4").intValue()); |
||||
} |
||||
|
||||
private void assertMapValuesCleared(TestMap message) { |
||||
assertEquals(0, message.getInt32ToInt32Field().size()); |
||||
assertEquals(0, message.getInt32ToStringField().size()); |
||||
assertEquals(0, message.getInt32ToBytesField().size()); |
||||
assertEquals(0, message.getInt32ToEnumField().size()); |
||||
assertEquals(0, message.getInt32ToMessageField().size()); |
||||
assertEquals(0, message.getStringToInt32Field().size()); |
||||
} |
||||
|
||||
public void testGettersAndSetters() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
TestMap message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
setMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testSerializeAndParse() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testMergeFrom() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
TestMap.Builder other = TestMap.newBuilder(); |
||||
other.mergeFrom(message); |
||||
assertMapValuesSet(other.build()); |
||||
} |
||||
|
||||
public void testEqualsAndHashCode() throws Exception { |
||||
// Test that generated equals() and hashCode() will disregard the order
|
||||
// of map entries when comparing/hashing map fields.
|
||||
|
||||
// We can't control the order of elements in a HashMap. The best we can do
|
||||
// here is to add elements in different order.
|
||||
TestMap.Builder b1 = TestMap.newBuilder(); |
||||
b1.getMutableInt32ToInt32Field().put(1, 2); |
||||
b1.getMutableInt32ToInt32Field().put(3, 4); |
||||
b1.getMutableInt32ToInt32Field().put(5, 6); |
||||
TestMap m1 = b1.build(); |
||||
|
||||
TestMap.Builder b2 = TestMap.newBuilder(); |
||||
b2.getMutableInt32ToInt32Field().put(5, 6); |
||||
b2.getMutableInt32ToInt32Field().put(1, 2); |
||||
b2.getMutableInt32ToInt32Field().put(3, 4); |
||||
TestMap m2 = b2.build(); |
||||
|
||||
assertEquals(m1, m2); |
||||
assertEquals(m1.hashCode(), m2.hashCode()); |
||||
|
||||
// Make sure we did compare map fields.
|
||||
b2.getMutableInt32ToInt32Field().put(1, 0); |
||||
m2 = b2.build(); |
||||
assertFalse(m1.equals(m2)); |
||||
// Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
|
||||
// to be different.
|
||||
} |
||||
|
||||
public void testUnknownEnumValues() throws Exception { |
||||
TestUnknownEnumValue.Builder builder = |
||||
TestUnknownEnumValue.newBuilder(); |
||||
builder.getMutableInt32ToInt32Field().put(1, 1); |
||||
builder.getMutableInt32ToInt32Field().put(2, 54321); |
||||
ByteString data = builder.build().toByteString(); |
||||
|
||||
TestMap message = TestMap.parseFrom(data); |
||||
// Entries with unknown enum values will be stored into UnknownFieldSet so
|
||||
// there is only one entry in the map.
|
||||
assertEquals(1, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); |
||||
// Serializing and parsing should preserve the unknown entry.
|
||||
data = message.toByteString(); |
||||
TestUnknownEnumValue messageWithUnknownEnums = |
||||
TestUnknownEnumValue.parseFrom(data); |
||||
assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); |
||||
assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,488 @@ |
||||
// 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 map_test.MapForProto2TestProto.TestMap; |
||||
import map_test.MapForProto2TestProto.TestMap.MessageValue; |
||||
import map_test.MapForProto2TestProto.TestUnknownEnumValue; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Unit tests for map fields in proto2 protos. |
||||
*/ |
||||
public class MapForProto2Test extends TestCase { |
||||
private void setMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 11); |
||||
builder.getMutableInt32ToInt32Field().put(2, 22); |
||||
builder.getMutableInt32ToInt32Field().put(3, 33); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "11"); |
||||
builder.getMutableInt32ToStringField().put(2, "22"); |
||||
builder.getMutableInt32ToStringField().put(3, "33"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); |
||||
builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); |
||||
builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); |
||||
builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(11).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
2, MessageValue.newBuilder().setValue(22).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
3, MessageValue.newBuilder().setValue(33).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 11); |
||||
builder.getMutableStringToInt32Field().put("2", 22); |
||||
builder.getMutableStringToInt32Field().put("3", 33); |
||||
} |
||||
|
||||
private void assertMapValuesSet(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("11", message.getInt32ToStringField().get(1)); |
||||
assertEquals("22", message.getInt32ToStringField().get(2)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(11, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(22, message.getStringToInt32Field().get("2").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
} |
||||
|
||||
private void updateMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 111); |
||||
builder.getMutableInt32ToInt32Field().remove(2); |
||||
builder.getMutableInt32ToInt32Field().put(4, 44); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "111"); |
||||
builder.getMutableInt32ToStringField().remove(2); |
||||
builder.getMutableInt32ToStringField().put(4, "44"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); |
||||
builder.getMutableInt32ToBytesField().remove(2); |
||||
builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().remove(2); |
||||
builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(111).build()); |
||||
builder.getMutableInt32ToMessageField().remove(2); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
4, MessageValue.newBuilder().setValue(44).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 111); |
||||
builder.getMutableStringToInt32Field().remove("2"); |
||||
builder.getMutableStringToInt32Field().put("4", 44); |
||||
} |
||||
|
||||
private void assertMapValuesUpdated(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("111", message.getInt32ToStringField().get(1)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
assertEquals("44", message.getInt32ToStringField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(111, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
assertEquals(44, message.getStringToInt32Field().get("4").intValue()); |
||||
} |
||||
|
||||
private void assertMapValuesCleared(TestMap message) { |
||||
assertEquals(0, message.getInt32ToInt32Field().size()); |
||||
assertEquals(0, message.getInt32ToStringField().size()); |
||||
assertEquals(0, message.getInt32ToBytesField().size()); |
||||
assertEquals(0, message.getInt32ToEnumField().size()); |
||||
assertEquals(0, message.getInt32ToMessageField().size()); |
||||
assertEquals(0, message.getStringToInt32Field().size()); |
||||
} |
||||
|
||||
public void testGettersAndSetters() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
TestMap message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
setMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testSerializeAndParse() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testMergeFrom() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
TestMap.Builder other = TestMap.newBuilder(); |
||||
other.mergeFrom(message); |
||||
assertMapValuesSet(other.build()); |
||||
} |
||||
|
||||
public void testEqualsAndHashCode() throws Exception { |
||||
// Test that generated equals() and hashCode() will disregard the order
|
||||
// of map entries when comparing/hashing map fields.
|
||||
|
||||
// We can't control the order of elements in a HashMap. The best we can do
|
||||
// here is to add elements in different order.
|
||||
TestMap.Builder b1 = TestMap.newBuilder(); |
||||
b1.getMutableInt32ToInt32Field().put(1, 2); |
||||
b1.getMutableInt32ToInt32Field().put(3, 4); |
||||
b1.getMutableInt32ToInt32Field().put(5, 6); |
||||
TestMap m1 = b1.build(); |
||||
|
||||
TestMap.Builder b2 = TestMap.newBuilder(); |
||||
b2.getMutableInt32ToInt32Field().put(5, 6); |
||||
b2.getMutableInt32ToInt32Field().put(1, 2); |
||||
b2.getMutableInt32ToInt32Field().put(3, 4); |
||||
TestMap m2 = b2.build(); |
||||
|
||||
assertEquals(m1, m2); |
||||
assertEquals(m1.hashCode(), m2.hashCode()); |
||||
|
||||
// Make sure we did compare map fields.
|
||||
b2.getMutableInt32ToInt32Field().put(1, 0); |
||||
m2 = b2.build(); |
||||
assertFalse(m1.equals(m2)); |
||||
// Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
|
||||
// to be different.
|
||||
} |
||||
|
||||
|
||||
// The following methods are used to test reflection API.
|
||||
|
||||
private static FieldDescriptor f(String name) { |
||||
return TestMap.getDescriptor().findFieldByName(name); |
||||
} |
||||
|
||||
private static Object getFieldValue(Message mapEntry, String name) { |
||||
FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); |
||||
return mapEntry.getField(field); |
||||
} |
||||
|
||||
private static Message.Builder setFieldValue( |
||||
Message.Builder mapEntry, String name, Object value) { |
||||
FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); |
||||
mapEntry.setField(field, value); |
||||
return mapEntry; |
||||
} |
||||
|
||||
private static void assertHasMapValues(Message message, String name, Map<?, ?> values) { |
||||
FieldDescriptor field = f(name); |
||||
for (Object entry : (List<?>) message.getField(field)) { |
||||
Message mapEntry = (Message) entry; |
||||
Object key = getFieldValue(mapEntry, "key"); |
||||
Object value = getFieldValue(mapEntry, "value"); |
||||
assertTrue(values.containsKey(key)); |
||||
assertEquals(value, values.get(key)); |
||||
} |
||||
assertEquals(values.size(), message.getRepeatedFieldCount(field)); |
||||
for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { |
||||
Message mapEntry = (Message) message.getRepeatedField(field, i); |
||||
Object key = getFieldValue(mapEntry, "key"); |
||||
Object value = getFieldValue(mapEntry, "value"); |
||||
assertTrue(values.containsKey(key)); |
||||
assertEquals(value, values.get(key)); |
||||
} |
||||
} |
||||
|
||||
private static <KeyType, ValueType> |
||||
Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { |
||||
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); |
||||
Message.Builder entryBuilder = builder.newBuilderForField(field); |
||||
FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); |
||||
FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); |
||||
entryBuilder.setField(keyField, key); |
||||
entryBuilder.setField(valueField, value); |
||||
return entryBuilder.build(); |
||||
} |
||||
|
||||
private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { |
||||
List<Message> entryList = new ArrayList<Message>(); |
||||
for (Map.Entry<?, ?> entry : values.entrySet()) { |
||||
entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); |
||||
} |
||||
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); |
||||
builder.setField(field, entryList); |
||||
} |
||||
|
||||
private static <KeyType, ValueType> |
||||
Map<KeyType, ValueType> mapForValues( |
||||
KeyType key1, ValueType value1, KeyType key2, ValueType value2) { |
||||
Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>(); |
||||
map.put(key1, value1); |
||||
map.put(key2, value2); |
||||
return map; |
||||
} |
||||
|
||||
public void testReflectionApi() throws Exception { |
||||
// In reflection API, map fields are just repeated message fields.
|
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
builder.getMutableInt32ToInt32Field().put(1, 2); |
||||
builder.getMutableInt32ToInt32Field().put(3, 4); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
11, MessageValue.newBuilder().setValue(22).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
33, MessageValue.newBuilder().setValue(44).build()); |
||||
TestMap message = builder.build(); |
||||
|
||||
// Test getField(), getRepeatedFieldCount(), getRepeatedField().
|
||||
assertHasMapValues(message, "int32_to_int32_field", |
||||
mapForValues(1, 2, 3, 4)); |
||||
assertHasMapValues(message, "int32_to_message_field", |
||||
mapForValues( |
||||
11, MessageValue.newBuilder().setValue(22).build(), |
||||
33, MessageValue.newBuilder().setValue(44).build())); |
||||
|
||||
// Test clearField()
|
||||
builder.clearField(f("int32_to_int32_field")); |
||||
builder.clearField(f("int32_to_message_field")); |
||||
message = builder.build(); |
||||
assertEquals(0, message.getInt32ToInt32Field().size()); |
||||
assertEquals(0, message.getInt32ToMessageField().size()); |
||||
|
||||
// Test setField()
|
||||
setMapValues(builder, "int32_to_int32_field", |
||||
mapForValues(11, 22, 33, 44)); |
||||
setMapValues(builder, "int32_to_message_field", |
||||
mapForValues( |
||||
111, MessageValue.newBuilder().setValue(222).build(), |
||||
333, MessageValue.newBuilder().setValue(444).build())); |
||||
message = builder.build(); |
||||
assertEquals(22, message.getInt32ToInt32Field().get(11).intValue()); |
||||
assertEquals(44, message.getInt32ToInt32Field().get(33).intValue()); |
||||
assertEquals(222, message.getInt32ToMessageField().get(111).getValue()); |
||||
assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); |
||||
|
||||
// Test addRepeatedField
|
||||
builder.addRepeatedField(f("int32_to_int32_field"), |
||||
newMapEntry(builder, "int32_to_int32_field", 55, 66)); |
||||
builder.addRepeatedField(f("int32_to_message_field"), |
||||
newMapEntry(builder, "int32_to_message_field", 555, |
||||
MessageValue.newBuilder().setValue(666).build())); |
||||
message = builder.build(); |
||||
assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); |
||||
assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); |
||||
|
||||
// Test addRepeatedField (overriding existing values)
|
||||
builder.addRepeatedField(f("int32_to_int32_field"), |
||||
newMapEntry(builder, "int32_to_int32_field", 55, 55)); |
||||
builder.addRepeatedField(f("int32_to_message_field"), |
||||
newMapEntry(builder, "int32_to_message_field", 555, |
||||
MessageValue.newBuilder().setValue(555).build())); |
||||
message = builder.build(); |
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); |
||||
assertEquals(555, message.getInt32ToMessageField().get(555).getValue()); |
||||
|
||||
// Test setRepeatedField
|
||||
for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { |
||||
Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); |
||||
int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); |
||||
int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); |
||||
// Swap key with value for each entry.
|
||||
Message.Builder mapEntryBuilder = mapEntry.toBuilder(); |
||||
setFieldValue(mapEntryBuilder, "key", oldValue); |
||||
setFieldValue(mapEntryBuilder, "value", oldKey); |
||||
builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); |
||||
} |
||||
message = builder.build(); |
||||
assertEquals(11, message.getInt32ToInt32Field().get(22).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); |
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); |
||||
} |
||||
|
||||
public void testTextFormat() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
String textData = TextFormat.printToString(message); |
||||
|
||||
builder = TestMap.newBuilder(); |
||||
TextFormat.merge(textData, builder); |
||||
message = builder.build(); |
||||
|
||||
assertMapValuesSet(message); |
||||
} |
||||
|
||||
public void testDynamicMessage() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
Message dynamicDefaultInstance = |
||||
DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); |
||||
Message dynamicMessage = dynamicDefaultInstance |
||||
.newBuilderForType().mergeFrom(message.toByteString()).build(); |
||||
|
||||
assertEquals(message, dynamicMessage); |
||||
assertEquals(message.hashCode(), dynamicMessage.hashCode()); |
||||
} |
||||
|
||||
public void testReflectionEqualsAndHashCode() throws Exception { |
||||
// Test that generated equals() and hashCode() will disregard the order
|
||||
// of map entries when comparing/hashing map fields.
|
||||
|
||||
// We use DynamicMessage to test reflection based equals()/hashCode().
|
||||
Message dynamicDefaultInstance = |
||||
DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); |
||||
FieldDescriptor field = f("int32_to_int32_field"); |
||||
|
||||
Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); |
||||
Message m1 = b1.build(); |
||||
|
||||
Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); |
||||
Message m2 = b2.build(); |
||||
|
||||
assertEquals(m1, m2); |
||||
assertEquals(m1.hashCode(), m2.hashCode()); |
||||
|
||||
// Make sure we did compare map fields.
|
||||
b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); |
||||
m2 = b2.build(); |
||||
assertFalse(m1.equals(m2)); |
||||
// Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
|
||||
// to be different.
|
||||
} |
||||
|
||||
public void testUnknownEnumValues() throws Exception { |
||||
TestUnknownEnumValue.Builder builder = |
||||
TestUnknownEnumValue.newBuilder(); |
||||
builder.getMutableInt32ToInt32Field().put(1, 1); |
||||
builder.getMutableInt32ToInt32Field().put(2, 54321); |
||||
ByteString data = builder.build().toByteString(); |
||||
|
||||
TestMap message = TestMap.parseFrom(data); |
||||
// Entries with unknown enum values will be stored into UnknownFieldSet so
|
||||
// there is only one entry in the map.
|
||||
assertEquals(1, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); |
||||
// UnknownFieldSet should not be empty.
|
||||
assertFalse(message.getUnknownFields().asMap().isEmpty()); |
||||
// Serializing and parsing should preserve the unknown entry.
|
||||
data = message.toByteString(); |
||||
TestUnknownEnumValue messageWithUnknownEnums = |
||||
TestUnknownEnumValue.parseFrom(data); |
||||
assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); |
||||
assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,569 @@ |
||||
// 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.EnumDescriptor; |
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor; |
||||
import com.google.protobuf.Descriptors.FieldDescriptor; |
||||
import map_test.MapTestProto.TestMap; |
||||
import map_test.MapTestProto.TestMap.MessageValue; |
||||
import map_test.MapTestProto.TestOnChangeEventPropagation; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Unit tests for map fields. |
||||
*/ |
||||
public class MapTest extends TestCase { |
||||
private void setMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 11); |
||||
builder.getMutableInt32ToInt32Field().put(2, 22); |
||||
builder.getMutableInt32ToInt32Field().put(3, 33); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "11"); |
||||
builder.getMutableInt32ToStringField().put(2, "22"); |
||||
builder.getMutableInt32ToStringField().put(3, "33"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); |
||||
builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); |
||||
builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); |
||||
builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(11).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
2, MessageValue.newBuilder().setValue(22).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
3, MessageValue.newBuilder().setValue(33).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 11); |
||||
builder.getMutableStringToInt32Field().put("2", 22); |
||||
builder.getMutableStringToInt32Field().put("3", 33); |
||||
} |
||||
|
||||
private void assertMapValuesSet(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("11", message.getInt32ToStringField().get(1)); |
||||
assertEquals("22", message.getInt32ToStringField().get(2)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(11, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(22, message.getStringToInt32Field().get("2").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
} |
||||
|
||||
private void updateMapValues(TestMap.Builder builder) { |
||||
builder.getMutableInt32ToInt32Field().put(1, 111); |
||||
builder.getMutableInt32ToInt32Field().remove(2); |
||||
builder.getMutableInt32ToInt32Field().put(4, 44); |
||||
|
||||
builder.getMutableInt32ToStringField().put(1, "111"); |
||||
builder.getMutableInt32ToStringField().remove(2); |
||||
builder.getMutableInt32ToStringField().put(4, "44"); |
||||
|
||||
builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); |
||||
builder.getMutableInt32ToBytesField().remove(2); |
||||
builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); |
||||
|
||||
builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); |
||||
builder.getMutableInt32ToEnumField().remove(2); |
||||
builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); |
||||
|
||||
builder.getMutableInt32ToMessageField().put( |
||||
1, MessageValue.newBuilder().setValue(111).build()); |
||||
builder.getMutableInt32ToMessageField().remove(2); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
4, MessageValue.newBuilder().setValue(44).build()); |
||||
|
||||
builder.getMutableStringToInt32Field().put("1", 111); |
||||
builder.getMutableStringToInt32Field().remove("2"); |
||||
builder.getMutableStringToInt32Field().put("4", 44); |
||||
} |
||||
|
||||
private void assertMapValuesUpdated(TestMap message) { |
||||
assertEquals(3, message.getInt32ToInt32Field().size()); |
||||
assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); |
||||
assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); |
||||
|
||||
assertEquals(3, message.getInt32ToStringField().size()); |
||||
assertEquals("111", message.getInt32ToStringField().get(1)); |
||||
assertEquals("33", message.getInt32ToStringField().get(3)); |
||||
assertEquals("44", message.getInt32ToStringField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToBytesField().size()); |
||||
assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); |
||||
assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); |
||||
assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToEnumField().size()); |
||||
assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); |
||||
assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); |
||||
|
||||
assertEquals(3, message.getInt32ToMessageField().size()); |
||||
assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); |
||||
assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); |
||||
assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); |
||||
|
||||
assertEquals(3, message.getStringToInt32Field().size()); |
||||
assertEquals(111, message.getStringToInt32Field().get("1").intValue()); |
||||
assertEquals(33, message.getStringToInt32Field().get("3").intValue()); |
||||
assertEquals(44, message.getStringToInt32Field().get("4").intValue()); |
||||
} |
||||
|
||||
private void assertMapValuesCleared(TestMap message) { |
||||
assertEquals(0, message.getInt32ToInt32Field().size()); |
||||
assertEquals(0, message.getInt32ToStringField().size()); |
||||
assertEquals(0, message.getInt32ToBytesField().size()); |
||||
assertEquals(0, message.getInt32ToEnumField().size()); |
||||
assertEquals(0, message.getInt32ToMessageField().size()); |
||||
assertEquals(0, message.getStringToInt32Field().size()); |
||||
} |
||||
|
||||
public void testGettersAndSetters() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
TestMap message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
setMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testSerializeAndParse() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesSet(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
updateMapValues(builder); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesUpdated(message); |
||||
|
||||
builder = message.toBuilder(); |
||||
builder.clear(); |
||||
message = builder.build(); |
||||
assertEquals(message.getSerializedSize(), message.toByteString().size()); |
||||
message = TestMap.PARSER.parseFrom(message.toByteString()); |
||||
assertMapValuesCleared(message); |
||||
} |
||||
|
||||
public void testMergeFrom() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
TestMap.Builder other = TestMap.newBuilder(); |
||||
other.mergeFrom(message); |
||||
assertMapValuesSet(other.build()); |
||||
} |
||||
|
||||
public void testEqualsAndHashCode() throws Exception { |
||||
// Test that generated equals() and hashCode() will disregard the order
|
||||
// of map entries when comparing/hashing map fields.
|
||||
|
||||
// We can't control the order of elements in a HashMap. The best we can do
|
||||
// here is to add elements in different order.
|
||||
TestMap.Builder b1 = TestMap.newBuilder(); |
||||
b1.getMutableInt32ToInt32Field().put(1, 2); |
||||
b1.getMutableInt32ToInt32Field().put(3, 4); |
||||
b1.getMutableInt32ToInt32Field().put(5, 6); |
||||
TestMap m1 = b1.build(); |
||||
|
||||
TestMap.Builder b2 = TestMap.newBuilder(); |
||||
b2.getMutableInt32ToInt32Field().put(5, 6); |
||||
b2.getMutableInt32ToInt32Field().put(1, 2); |
||||
b2.getMutableInt32ToInt32Field().put(3, 4); |
||||
TestMap m2 = b2.build(); |
||||
|
||||
assertEquals(m1, m2); |
||||
assertEquals(m1.hashCode(), m2.hashCode()); |
||||
|
||||
// Make sure we did compare map fields.
|
||||
b2.getMutableInt32ToInt32Field().put(1, 0); |
||||
m2 = b2.build(); |
||||
assertFalse(m1.equals(m2)); |
||||
// Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
|
||||
// to be different.
|
||||
} |
||||
|
||||
|
||||
public void testNestedBuilderOnChangeEventPropagation() { |
||||
TestOnChangeEventPropagation.Builder parent = |
||||
TestOnChangeEventPropagation.newBuilder(); |
||||
parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 2); |
||||
TestOnChangeEventPropagation message = parent.build(); |
||||
assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); |
||||
|
||||
// Make a change using nested builder.
|
||||
parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 3); |
||||
|
||||
// Should be able to observe the change.
|
||||
message = parent.build(); |
||||
assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); |
||||
|
||||
// Make another change using mergeFrom()
|
||||
TestMap.Builder other = TestMap.newBuilder(); |
||||
other.getMutableInt32ToInt32Field().put(1, 4); |
||||
parent.getOptionalMessageBuilder().mergeFrom(other.build()); |
||||
|
||||
// Should be able to observe the change.
|
||||
message = parent.build(); |
||||
assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); |
||||
|
||||
// Make yet another change by clearing the nested builder.
|
||||
parent.getOptionalMessageBuilder().clear(); |
||||
|
||||
// Should be able to observe the change.
|
||||
message = parent.build(); |
||||
assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size()); |
||||
} |
||||
|
||||
// The following methods are used to test reflection API.
|
||||
|
||||
private static FieldDescriptor f(String name) { |
||||
return TestMap.getDescriptor().findFieldByName(name); |
||||
} |
||||
|
||||
private static Object getFieldValue(Message mapEntry, String name) { |
||||
FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); |
||||
return mapEntry.getField(field); |
||||
} |
||||
|
||||
private static Message.Builder setFieldValue( |
||||
Message.Builder mapEntry, String name, Object value) { |
||||
FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); |
||||
mapEntry.setField(field, value); |
||||
return mapEntry; |
||||
} |
||||
|
||||
private static void assertHasMapValues(Message message, String name, Map<?, ?> values) { |
||||
FieldDescriptor field = f(name); |
||||
for (Object entry : (List<?>) message.getField(field)) { |
||||
Message mapEntry = (Message) entry; |
||||
Object key = getFieldValue(mapEntry, "key"); |
||||
Object value = getFieldValue(mapEntry, "value"); |
||||
assertTrue(values.containsKey(key)); |
||||
assertEquals(value, values.get(key)); |
||||
} |
||||
assertEquals(values.size(), message.getRepeatedFieldCount(field)); |
||||
for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { |
||||
Message mapEntry = (Message) message.getRepeatedField(field, i); |
||||
Object key = getFieldValue(mapEntry, "key"); |
||||
Object value = getFieldValue(mapEntry, "value"); |
||||
assertTrue(values.containsKey(key)); |
||||
assertEquals(value, values.get(key)); |
||||
} |
||||
} |
||||
|
||||
private static <KeyType, ValueType> |
||||
Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { |
||||
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); |
||||
Message.Builder entryBuilder = builder.newBuilderForField(field); |
||||
FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); |
||||
FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); |
||||
entryBuilder.setField(keyField, key); |
||||
entryBuilder.setField(valueField, value); |
||||
return entryBuilder.build(); |
||||
} |
||||
|
||||
private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { |
||||
List<Message> entryList = new ArrayList<Message>(); |
||||
for (Map.Entry<?, ?> entry : values.entrySet()) { |
||||
entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); |
||||
} |
||||
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); |
||||
builder.setField(field, entryList); |
||||
} |
||||
|
||||
private static <KeyType, ValueType> |
||||
Map<KeyType, ValueType> mapForValues( |
||||
KeyType key1, ValueType value1, KeyType key2, ValueType value2) { |
||||
Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>(); |
||||
map.put(key1, value1); |
||||
map.put(key2, value2); |
||||
return map; |
||||
} |
||||
|
||||
public void testReflectionApi() throws Exception { |
||||
// In reflection API, map fields are just repeated message fields.
|
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
builder.getMutableInt32ToInt32Field().put(1, 2); |
||||
builder.getMutableInt32ToInt32Field().put(3, 4); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
11, MessageValue.newBuilder().setValue(22).build()); |
||||
builder.getMutableInt32ToMessageField().put( |
||||
33, MessageValue.newBuilder().setValue(44).build()); |
||||
TestMap message = builder.build(); |
||||
|
||||
// Test getField(), getRepeatedFieldCount(), getRepeatedField().
|
||||
assertHasMapValues(message, "int32_to_int32_field", |
||||
mapForValues(1, 2, 3, 4)); |
||||
assertHasMapValues(message, "int32_to_message_field", |
||||
mapForValues( |
||||
11, MessageValue.newBuilder().setValue(22).build(), |
||||
33, MessageValue.newBuilder().setValue(44).build())); |
||||
|
||||
// Test clearField()
|
||||
builder.clearField(f("int32_to_int32_field")); |
||||
builder.clearField(f("int32_to_message_field")); |
||||
message = builder.build(); |
||||
assertEquals(0, message.getInt32ToInt32Field().size()); |
||||
assertEquals(0, message.getInt32ToMessageField().size()); |
||||
|
||||
// Test setField()
|
||||
setMapValues(builder, "int32_to_int32_field", |
||||
mapForValues(11, 22, 33, 44)); |
||||
setMapValues(builder, "int32_to_message_field", |
||||
mapForValues( |
||||
111, MessageValue.newBuilder().setValue(222).build(), |
||||
333, MessageValue.newBuilder().setValue(444).build())); |
||||
message = builder.build(); |
||||
assertEquals(22, message.getInt32ToInt32Field().get(11).intValue()); |
||||
assertEquals(44, message.getInt32ToInt32Field().get(33).intValue()); |
||||
assertEquals(222, message.getInt32ToMessageField().get(111).getValue()); |
||||
assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); |
||||
|
||||
// Test addRepeatedField
|
||||
builder.addRepeatedField(f("int32_to_int32_field"), |
||||
newMapEntry(builder, "int32_to_int32_field", 55, 66)); |
||||
builder.addRepeatedField(f("int32_to_message_field"), |
||||
newMapEntry(builder, "int32_to_message_field", 555, |
||||
MessageValue.newBuilder().setValue(666).build())); |
||||
message = builder.build(); |
||||
assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); |
||||
assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); |
||||
|
||||
// Test addRepeatedField (overriding existing values)
|
||||
builder.addRepeatedField(f("int32_to_int32_field"), |
||||
newMapEntry(builder, "int32_to_int32_field", 55, 55)); |
||||
builder.addRepeatedField(f("int32_to_message_field"), |
||||
newMapEntry(builder, "int32_to_message_field", 555, |
||||
MessageValue.newBuilder().setValue(555).build())); |
||||
message = builder.build(); |
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); |
||||
assertEquals(555, message.getInt32ToMessageField().get(555).getValue()); |
||||
|
||||
// Test setRepeatedField
|
||||
for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { |
||||
Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); |
||||
int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); |
||||
int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); |
||||
// Swap key with value for each entry.
|
||||
Message.Builder mapEntryBuilder = mapEntry.toBuilder(); |
||||
setFieldValue(mapEntryBuilder, "key", oldValue); |
||||
setFieldValue(mapEntryBuilder, "value", oldKey); |
||||
builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); |
||||
} |
||||
message = builder.build(); |
||||
assertEquals(11, message.getInt32ToInt32Field().get(22).intValue()); |
||||
assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); |
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); |
||||
} |
||||
|
||||
public void testTextFormat() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
String textData = TextFormat.printToString(message); |
||||
|
||||
builder = TestMap.newBuilder(); |
||||
TextFormat.merge(textData, builder); |
||||
message = builder.build(); |
||||
|
||||
assertMapValuesSet(message); |
||||
} |
||||
|
||||
public void testDynamicMessage() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
setMapValues(builder); |
||||
TestMap message = builder.build(); |
||||
|
||||
Message dynamicDefaultInstance = |
||||
DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); |
||||
Message dynamicMessage = dynamicDefaultInstance |
||||
.newBuilderForType().mergeFrom(message.toByteString()).build(); |
||||
|
||||
assertEquals(message, dynamicMessage); |
||||
assertEquals(message.hashCode(), dynamicMessage.hashCode()); |
||||
} |
||||
|
||||
public void testReflectionEqualsAndHashCode() throws Exception { |
||||
// Test that generated equals() and hashCode() will disregard the order
|
||||
// of map entries when comparing/hashing map fields.
|
||||
|
||||
// We use DynamicMessage to test reflection based equals()/hashCode().
|
||||
Message dynamicDefaultInstance = |
||||
DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); |
||||
FieldDescriptor field = f("int32_to_int32_field"); |
||||
|
||||
Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); |
||||
b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); |
||||
Message m1 = b1.build(); |
||||
|
||||
Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); |
||||
b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); |
||||
Message m2 = b2.build(); |
||||
|
||||
assertEquals(m1, m2); |
||||
assertEquals(m1.hashCode(), m2.hashCode()); |
||||
|
||||
// Make sure we did compare map fields.
|
||||
b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); |
||||
m2 = b2.build(); |
||||
assertFalse(m1.equals(m2)); |
||||
// Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
|
||||
// to be different.
|
||||
} |
||||
|
||||
public void testUnknownEnumValues() throws Exception { |
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
builder.getMutableInt32ToEnumFieldValue().put(0, 0); |
||||
builder.getMutableInt32ToEnumFieldValue().put(1, 1); |
||||
builder.getMutableInt32ToEnumFieldValue().put(2, 1000); // unknown value.
|
||||
TestMap message = builder.build(); |
||||
|
||||
assertEquals(TestMap.EnumValue.FOO, |
||||
message.getInt32ToEnumField().get(0)); |
||||
assertEquals(TestMap.EnumValue.BAR, |
||||
message.getInt32ToEnumField().get(1)); |
||||
assertEquals(TestMap.EnumValue.UNRECOGNIZED, |
||||
message.getInt32ToEnumField().get(2)); |
||||
assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); |
||||
|
||||
// Unknown enum values should be preserved after:
|
||||
// 1. Serialization and parsing.
|
||||
// 2. toBuild().
|
||||
// 3. mergeFrom().
|
||||
message = TestMap.parseFrom(message.toByteString()); |
||||
assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); |
||||
builder = message.toBuilder(); |
||||
assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); |
||||
builder = TestMap.newBuilder().mergeFrom(message); |
||||
assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); |
||||
|
||||
// hashCode()/equals() should take unknown enum values into account.
|
||||
builder.getMutableInt32ToEnumFieldValue().put(2, 1001); |
||||
TestMap message2 = builder.build(); |
||||
assertFalse(message.hashCode() == message2.hashCode()); |
||||
assertFalse(message.equals(message2)); |
||||
// Unknown values will be converted to UNRECOGNIZED so the resulted enum map
|
||||
// should be the same.
|
||||
assertTrue(message.getInt32ToEnumField().equals(message2.getInt32ToEnumField())); |
||||
} |
||||
|
||||
public void testUnknownEnumValuesInReflectionApi() throws Exception { |
||||
Descriptor descriptor = TestMap.getDescriptor(); |
||||
EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor(); |
||||
FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field"); |
||||
|
||||
Map<Integer, Integer> data = new HashMap<Integer, Integer>(); |
||||
data.put(0, 0); |
||||
data.put(1, 1); |
||||
data.put(2, 1000); // unknown value.
|
||||
|
||||
TestMap.Builder builder = TestMap.newBuilder(); |
||||
for (Map.Entry<Integer, Integer> entry : data.entrySet()) { |
||||
builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue()); |
||||
} |
||||
|
||||
// Try to read unknown enum values using reflection API.
|
||||
for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) { |
||||
Message mapEntry = (Message) builder.getRepeatedField(field, i); |
||||
int key = ((Integer) getFieldValue(mapEntry, "key")).intValue(); |
||||
int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber(); |
||||
assertEquals(data.get(key).intValue(), value); |
||||
Message.Builder mapEntryBuilder = mapEntry.toBuilder(); |
||||
// Increase the value by 1.
|
||||
setFieldValue(mapEntryBuilder, "value", |
||||
enumDescriptor.findValueByNumberCreatingIfUnknown(value + 1)); |
||||
builder.setRepeatedField(field, i, mapEntryBuilder.build()); |
||||
} |
||||
|
||||
// Verify that enum values have been successfully updated.
|
||||
TestMap message = builder.build(); |
||||
for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValue().entrySet()) { |
||||
assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,255 @@ |
||||
// 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.EnumDescriptor; |
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor; |
||||
import com.google.protobuf.Descriptors.FieldDescriptor; |
||||
import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; |
||||
import com.google.protobuf.TextFormat.ParseException; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Unit tests for protos that keep unknown enum values rather than discard |
||||
* them as unknown fields. |
||||
*/ |
||||
public class UnknownEnumValueTest extends TestCase { |
||||
public void testUnknownEnumValues() throws Exception { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalNestedEnumValue(4321); |
||||
builder.addRepeatedNestedEnumValue(5432); |
||||
builder.addPackedNestedEnumValue(6543); |
||||
TestAllTypes message = builder.build(); |
||||
assertEquals(4321, message.getOptionalNestedEnumValue()); |
||||
assertEquals(5432, message.getRepeatedNestedEnumValue(0)); |
||||
assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue()); |
||||
assertEquals(6543, message.getPackedNestedEnumValue(0)); |
||||
// Returns UNRECOGNIZED if an enum type is requested.
|
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum()); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0)); |
||||
|
||||
// Test serialization and parsing.
|
||||
ByteString data = message.toByteString(); |
||||
message = TestAllTypes.parseFrom(data); |
||||
assertEquals(4321, message.getOptionalNestedEnumValue()); |
||||
assertEquals(5432, message.getRepeatedNestedEnumValue(0)); |
||||
assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue()); |
||||
assertEquals(6543, message.getPackedNestedEnumValue(0)); |
||||
// Returns UNRECOGNIZED if an enum type is requested.
|
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum()); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0)); |
||||
|
||||
// Test toBuilder().
|
||||
builder = message.toBuilder(); |
||||
assertEquals(4321, builder.getOptionalNestedEnumValue()); |
||||
assertEquals(5432, builder.getRepeatedNestedEnumValue(0)); |
||||
assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue()); |
||||
assertEquals(6543, builder.getPackedNestedEnumValue(0)); |
||||
// Returns UNRECOGNIZED if an enum type is requested.
|
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum()); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0)); |
||||
|
||||
// Test mergeFrom().
|
||||
builder = TestAllTypes.newBuilder().mergeFrom(message); |
||||
assertEquals(4321, builder.getOptionalNestedEnumValue()); |
||||
assertEquals(5432, builder.getRepeatedNestedEnumValue(0)); |
||||
assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue()); |
||||
assertEquals(6543, builder.getPackedNestedEnumValue(0)); |
||||
// Returns UNRECOGNIZED if an enum type is requested.
|
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum()); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0)); |
||||
assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0)); |
||||
|
||||
// Test equals() and hashCode()
|
||||
TestAllTypes sameMessage = builder.build(); |
||||
assertEquals(message, sameMessage); |
||||
assertEquals(message.hashCode(), sameMessage.hashCode()); |
||||
|
||||
// Getting the numeric value of UNRECOGNIZED will throw an exception.
|
||||
try { |
||||
TestAllTypes.NestedEnum.UNRECOGNIZED.getNumber(); |
||||
fail("Exception is expected."); |
||||
} catch (IllegalArgumentException e) { |
||||
// Expected.
|
||||
} |
||||
|
||||
// Setting an enum field to an UNRECOGNIZED value will throw an exception.
|
||||
try { |
||||
builder.setOptionalNestedEnum(builder.getOptionalNestedEnum()); |
||||
fail("Exception is expected."); |
||||
} catch (IllegalArgumentException e) { |
||||
// Expected.
|
||||
} |
||||
try { |
||||
builder.addRepeatedNestedEnum(builder.getOptionalNestedEnum()); |
||||
fail("Exception is expected."); |
||||
} catch (IllegalArgumentException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testUnknownEnumValueInReflectionApi() throws Exception { |
||||
Descriptor descriptor = TestAllTypes.getDescriptor(); |
||||
FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); |
||||
FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum"); |
||||
FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum"); |
||||
EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); |
||||
|
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setField(optionalNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(4321)); |
||||
builder.addRepeatedField(repeatedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(5432)); |
||||
builder.addRepeatedField(packedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(6543)); |
||||
TestAllTypes message = builder.build(); |
||||
|
||||
// Getters will return unknown enum values as EnumValueDescriptor.
|
||||
EnumValueDescriptor unknown4321 = |
||||
(EnumValueDescriptor) message.getField(optionalNestedEnumField); |
||||
EnumValueDescriptor unknown5432 = |
||||
(EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0); |
||||
EnumValueDescriptor unknown6543 = |
||||
(EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0); |
||||
assertEquals(4321, unknown4321.getNumber()); |
||||
assertEquals(5432, unknown5432.getNumber()); |
||||
assertEquals(6543, unknown6543.getNumber()); |
||||
|
||||
// Unknown EnumValueDescriptor will map to UNRECOGNIZED.
|
||||
assertEquals( |
||||
TestAllTypes.NestedEnum.valueOf(unknown4321), |
||||
TestAllTypes.NestedEnum.UNRECOGNIZED); |
||||
assertEquals( |
||||
TestAllTypes.NestedEnum.valueOf(unknown5432), |
||||
TestAllTypes.NestedEnum.UNRECOGNIZED); |
||||
assertEquals( |
||||
TestAllTypes.NestedEnum.valueOf(unknown6543), |
||||
TestAllTypes.NestedEnum.UNRECOGNIZED); |
||||
|
||||
// Setters also accept unknown EnumValueDescriptor.
|
||||
builder.setField(optionalNestedEnumField, unknown6543); |
||||
builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321); |
||||
builder.setRepeatedField(packedNestedEnumField, 0, unknown5432); |
||||
message = builder.build(); |
||||
// Like other descriptors, unknown EnumValueDescriptor can be compared by
|
||||
// object identity.
|
||||
assertTrue(unknown6543 == message.getField(optionalNestedEnumField)); |
||||
assertTrue(unknown4321 == message.getRepeatedField(repeatedNestedEnumField, 0)); |
||||
assertTrue(unknown5432 == message.getRepeatedField(packedNestedEnumField, 0)); |
||||
} |
||||
|
||||
public void testUnknownEnumValueWithDynamicMessage() throws Exception { |
||||
Descriptor descriptor = TestAllTypes.getDescriptor(); |
||||
FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum"); |
||||
FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum"); |
||||
FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum"); |
||||
EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); |
||||
|
||||
Message dynamicMessageDefaultInstance = DynamicMessage.getDefaultInstance(descriptor); |
||||
|
||||
Message.Builder builder = dynamicMessageDefaultInstance.newBuilderForType(); |
||||
builder.setField(optionalNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(4321)); |
||||
builder.addRepeatedField(repeatedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(5432)); |
||||
builder.addRepeatedField(packedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(6543)); |
||||
Message message = builder.build(); |
||||
assertEquals(4321, |
||||
((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber()); |
||||
assertEquals(5432, |
||||
((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber()); |
||||
assertEquals(6543, |
||||
((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber()); |
||||
|
||||
// Test reflection based serialization/parsing implementation.
|
||||
ByteString data = message.toByteString(); |
||||
message = dynamicMessageDefaultInstance |
||||
.newBuilderForType() |
||||
.mergeFrom(data) |
||||
.build(); |
||||
assertEquals(4321, |
||||
((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber()); |
||||
assertEquals(5432, |
||||
((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber()); |
||||
assertEquals(6543, |
||||
((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber()); |
||||
|
||||
// Test reflection based equals()/hashCode().
|
||||
builder = dynamicMessageDefaultInstance.newBuilderForType(); |
||||
builder.setField(optionalNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(4321)); |
||||
builder.addRepeatedField(repeatedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(5432)); |
||||
builder.addRepeatedField(packedNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(6543)); |
||||
Message sameMessage = builder.build(); |
||||
assertEquals(message, sameMessage); |
||||
assertEquals(message.hashCode(), sameMessage.hashCode()); |
||||
builder.setField(optionalNestedEnumField, |
||||
enumType.findValueByNumberCreatingIfUnknown(0)); |
||||
Message differentMessage = builder.build(); |
||||
assertFalse(message.equals(differentMessage)); |
||||
} |
||||
|
||||
public void testUnknownEnumValuesInTextFormat() { |
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
||||
builder.setOptionalNestedEnumValue(4321); |
||||
builder.addRepeatedNestedEnumValue(5432); |
||||
builder.addPackedNestedEnumValue(6543); |
||||
TestAllTypes message = builder.build(); |
||||
|
||||
// We can print a message with unknown enum values.
|
||||
String textData = TextFormat.printToString(message); |
||||
assertEquals( |
||||
"optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n" |
||||
+ "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n" |
||||
+ "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n", textData); |
||||
|
||||
// Parsing unknown enum values will fail just like parsing other kinds of
|
||||
// unknown fields.
|
||||
try { |
||||
TextFormat.merge(textData, builder); |
||||
fail(); |
||||
} catch (ParseException e) { |
||||
// expected.
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,317 @@ |
||||
// 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 protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash; |
||||
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; |
||||
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
|
||||
/** |
||||
* Tests for {@link UnknownFieldSetLite}. |
||||
* |
||||
* @author dweis@google.com (Daniel Weis) |
||||
*/ |
||||
public class UnknownFieldSetLiteTest extends TestCase { |
||||
|
||||
public void testNoDataIsDefaultInstance() { |
||||
assertSame( |
||||
UnknownFieldSetLite.getDefaultInstance(), |
||||
UnknownFieldSetLite.newBuilder() |
||||
.build()); |
||||
} |
||||
|
||||
public void testDefaultInstance() { |
||||
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); |
||||
|
||||
assertEquals(0, unknownFields.getSerializedSize()); |
||||
assertEquals(ByteString.EMPTY, toByteString(unknownFields)); |
||||
} |
||||
|
||||
public void testMergeFieldFrom() throws IOException { |
||||
Foo foo = Foo.newBuilder() |
||||
.setValue(2) |
||||
.build(); |
||||
|
||||
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); |
||||
|
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeFieldFrom(input.readTag(), input); |
||||
|
||||
assertEquals(foo.toByteString(), toByteString(builder.build())); |
||||
} |
||||
|
||||
public void testSerializedSize() throws IOException { |
||||
Foo foo = Foo.newBuilder() |
||||
.setValue(2) |
||||
.build(); |
||||
|
||||
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); |
||||
|
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeFieldFrom(input.readTag(), input); |
||||
|
||||
assertEquals(foo.toByteString().size(), builder.build().getSerializedSize()); |
||||
} |
||||
|
||||
public void testMergeVarintField() throws IOException { |
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeVarintField(10, 2); |
||||
|
||||
CodedInputStream input = |
||||
CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); |
||||
|
||||
int tag = input.readTag(); |
||||
assertEquals(10, WireFormat.getTagFieldNumber(tag)); |
||||
assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); |
||||
assertEquals(2, input.readUInt64()); |
||||
assertTrue(input.isAtEnd()); |
||||
} |
||||
|
||||
public void testMergeVarintField_negative() throws IOException { |
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeVarintField(10, -6); |
||||
|
||||
CodedInputStream input = |
||||
CodedInputStream.newInstance(toByteString(builder.build()).toByteArray()); |
||||
|
||||
int tag = input.readTag(); |
||||
assertEquals(10, WireFormat.getTagFieldNumber(tag)); |
||||
assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); |
||||
assertEquals(-6, input.readUInt64()); |
||||
assertTrue(input.isAtEnd()); |
||||
} |
||||
|
||||
public void testEqualsAndHashCode() { |
||||
UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder(); |
||||
builder1.mergeVarintField(10, 2); |
||||
UnknownFieldSetLite unknownFields1 = builder1.build(); |
||||
|
||||
UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder(); |
||||
builder2.mergeVarintField(10, 2); |
||||
UnknownFieldSetLite unknownFields2 = builder2.build(); |
||||
|
||||
assertEquals(unknownFields1, unknownFields2); |
||||
assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode()); |
||||
assertFalse(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance())); |
||||
assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode()); |
||||
} |
||||
|
||||
public void testConcat() throws IOException { |
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeVarintField(10, 2); |
||||
UnknownFieldSetLite unknownFields = builder.build(); |
||||
|
||||
unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields); |
||||
|
||||
CodedInputStream input = |
||||
CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); |
||||
|
||||
int tag = input.readTag(); |
||||
assertEquals(10, WireFormat.getTagFieldNumber(tag)); |
||||
assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); |
||||
assertEquals(2, input.readUInt64()); |
||||
assertFalse(input.isAtEnd()); |
||||
input.readTag(); |
||||
assertEquals(10, WireFormat.getTagFieldNumber(tag)); |
||||
assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag)); |
||||
assertEquals(2, input.readUInt64()); |
||||
assertTrue(input.isAtEnd()); |
||||
} |
||||
|
||||
public void testConcat_empty() { |
||||
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat( |
||||
UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); |
||||
|
||||
assertEquals(0, unknownFields.getSerializedSize()); |
||||
assertEquals(ByteString.EMPTY, toByteString(unknownFields)); |
||||
} |
||||
|
||||
public void testBuilderReuse() throws IOException { |
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.mergeVarintField(10, 2); |
||||
builder.build(); |
||||
|
||||
try { |
||||
builder.build(); |
||||
fail(); |
||||
} catch (IllegalStateException e) { |
||||
// Expected.
|
||||
} |
||||
|
||||
try { |
||||
builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0])); |
||||
fail(); |
||||
} catch (IllegalStateException e) { |
||||
// Expected.
|
||||
} |
||||
|
||||
try { |
||||
builder.mergeVarintField(5, 1); |
||||
fail(); |
||||
} catch (IllegalStateException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testBuilderReuse_empty() { |
||||
UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); |
||||
builder.build(); |
||||
|
||||
try { |
||||
builder.build(); |
||||
fail(); |
||||
} catch (IllegalStateException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testRoundTrips() throws InvalidProtocolBufferException { |
||||
Foo foo = Foo.newBuilder() |
||||
.setValue(1) |
||||
.setExtension(Bar.fooExt, Bar.newBuilder() |
||||
.setName("name") |
||||
.build()) |
||||
.setExtension(LiteEqualsAndHash.varint, 22) |
||||
.setExtension(LiteEqualsAndHash.fixed32, 44) |
||||
.setExtension(LiteEqualsAndHash.fixed64, 66L) |
||||
.setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder() |
||||
.setGroupValue("value") |
||||
.build()) |
||||
.build(); |
||||
|
||||
Foo copy = Foo.parseFrom(foo.toByteArray()); |
||||
|
||||
assertEquals(foo.getSerializedSize(), copy.getSerializedSize()); |
||||
assertFalse(foo.equals(copy)); |
||||
|
||||
Foo secondCopy = Foo.parseFrom(foo.toByteArray()); |
||||
assertEquals(copy, secondCopy); |
||||
|
||||
ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); |
||||
LiteEqualsAndHash.registerAllExtensions(extensionRegistry); |
||||
Foo copyOfCopy = Foo.parseFrom(copy.toByteArray(), extensionRegistry); |
||||
|
||||
assertEquals(foo, copyOfCopy); |
||||
} |
||||
|
||||
public void testMalformedBytes() { |
||||
try { |
||||
Foo.parseFrom("this is a malformed protocol buffer".getBytes(StandardCharsets.UTF_8)); |
||||
fail(); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testMissingStartGroupTag() throws IOException { |
||||
ByteString.Output byteStringOutput = ByteString.newOutput(); |
||||
CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); |
||||
output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); |
||||
output.writeTag(100, WireFormat.WIRETYPE_END_GROUP); |
||||
output.flush(); |
||||
|
||||
try { |
||||
Foo.parseFrom(byteStringOutput.toByteString()); |
||||
fail(); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testMissingEndGroupTag() throws IOException { |
||||
ByteString.Output byteStringOutput = ByteString.newOutput(); |
||||
CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); |
||||
output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); |
||||
output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); |
||||
output.flush(); |
||||
|
||||
try { |
||||
Foo.parseFrom(byteStringOutput.toByteString()); |
||||
fail(); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testMismatchingGroupTags() throws IOException { |
||||
ByteString.Output byteStringOutput = ByteString.newOutput(); |
||||
CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); |
||||
output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); |
||||
output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); |
||||
output.writeTag(101, WireFormat.WIRETYPE_END_GROUP); |
||||
output.flush(); |
||||
|
||||
try { |
||||
Foo.parseFrom(byteStringOutput.toByteString()); |
||||
fail(); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
public void testTruncatedInput() { |
||||
Foo foo = Foo.newBuilder() |
||||
.setValue(1) |
||||
.setExtension(Bar.fooExt, Bar.newBuilder() |
||||
.setName("name") |
||||
.build()) |
||||
.setExtension(LiteEqualsAndHash.varint, 22) |
||||
.setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder() |
||||
.setGroupValue("value") |
||||
.build()) |
||||
.build(); |
||||
|
||||
try { |
||||
Foo.parseFrom(foo.toByteString().substring(0, foo.toByteString().size() - 10)); |
||||
fail(); |
||||
} catch (InvalidProtocolBufferException e) { |
||||
// Expected.
|
||||
} |
||||
} |
||||
|
||||
private ByteString toByteString(UnknownFieldSetLite unknownFields) { |
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
||||
CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); |
||||
try { |
||||
unknownFields.writeTo(output); |
||||
output.flush(); |
||||
} catch (IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
return ByteString.copyFrom(byteArrayOutputStream.toByteArray()); |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package field_presence_test; |
||||
|
||||
import "google/protobuf/unittest.proto"; |
||||
|
||||
option java_package = "com.google.protobuf"; |
||||
option java_outer_classname = "FieldPresenceTestProto"; |
||||
option java_generate_equals_and_hash = true; |
||||
|
||||
message TestAllTypes { |
||||
enum NestedEnum { |
||||
FOO = 0; |
||||
BAR = 1; |
||||
BAZ = 2; |
||||
} |
||||
message NestedMessage { |
||||
optional int32 value = 1; |
||||
} |
||||
|
||||
optional int32 optional_int32 = 1; |
||||
optional string optional_string = 2; |
||||
optional bytes optional_bytes = 3; |
||||
optional NestedEnum optional_nested_enum = 4; |
||||
optional NestedMessage optional_nested_message = 5; |
||||
optional protobuf_unittest.TestRequired optional_proto2_message = 6; |
||||
|
||||
oneof oneof_field { |
||||
int32 oneof_int32 = 11; |
||||
uint32 oneof_uint32 = 12; |
||||
string oneof_string = 13; |
||||
bytes oneof_bytes = 14; |
||||
NestedEnum oneof_nested_enum = 15; |
||||
NestedMessage oneof_nested_message = 16; |
||||
protobuf_unittest.TestRequired oneof_proto2_message = 17; |
||||
} |
||||
|
||||
repeated int32 repeated_int32 = 21; |
||||
repeated string repeated_string = 22; |
||||
repeated bytes repeated_bytes = 23; |
||||
repeated NestedEnum repeated_nested_enum = 24; |
||||
repeated NestedMessage repeated_nested_message = 25; |
||||
repeated protobuf_unittest.TestRequired repeated_proto2_message = 26; |
||||
repeated NestedEnum packed_nested_enum = 27 [packed = true]; |
||||
} |
||||
|
||||
message TestOptionalFieldsOnly { |
||||
optional int32 optional_int32 = 1; |
||||
optional string optional_string = 2; |
||||
optional bytes optional_bytes = 3; |
||||
optional TestAllTypes.NestedEnum optional_nested_enum = 4; |
||||
optional TestAllTypes.NestedMessage optional_nested_message = 5; |
||||
optional protobuf_unittest.TestRequired optional_proto2_message = 6; |
||||
} |
||||
|
||||
message TestRepeatedFieldsOnly { |
||||
repeated int32 repeated_int32 = 21; |
||||
repeated string repeated_string = 22; |
||||
repeated bytes repeated_bytes = 23; |
||||
repeated TestAllTypes.NestedEnum repeated_nested_enum = 24; |
||||
repeated TestAllTypes.NestedMessage repeated_nested_message = 25; |
||||
repeated protobuf_unittest.TestRequired repeated_proto2_message = 26; |
||||
} |
@ -0,0 +1,63 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
|
||||
option java_outer_classname = "MapForProto2TestProto"; |
||||
option java_generate_equals_and_hash = true; |
||||
|
||||
message TestMap { |
||||
message MessageValue { |
||||
optional int32 value = 1; |
||||
} |
||||
enum EnumValue { |
||||
FOO = 0; |
||||
BAR = 1; |
||||
BAZ = 2; |
||||
QUX = 3; |
||||
} |
||||
|
||||
map<int32, int32> int32_to_int32_field = 1; |
||||
map<int32, string> int32_to_string_field = 2; |
||||
map<int32, bytes> int32_to_bytes_field = 3; |
||||
map<int32, EnumValue> int32_to_enum_field = 4; |
||||
map<int32, MessageValue> int32_to_message_field = 5; |
||||
map<string, int32> string_to_int32_field = 6; |
||||
} |
||||
|
||||
message TestUnknownEnumValue { |
||||
// Wire-compatible with TestMap.int32_to_enum_field so we can test the |
||||
// parsing behavior of TestMap regarding unknown enum values. |
||||
map<int32, int32> int32_to_int32_field = 4; |
||||
} |
||||
package map_for_proto2_lite_test; |
||||
option java_package = "map_lite_test"; |
||||
option optimize_for = LITE_RUNTIME; |
@ -0,0 +1,62 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
package map_for_proto2_test; |
||||
|
||||
option java_package = "map_test"; |
||||
option java_outer_classname = "MapForProto2TestProto"; |
||||
option java_generate_equals_and_hash = true; |
||||
|
||||
message TestMap { |
||||
message MessageValue { |
||||
optional int32 value = 1; |
||||
} |
||||
enum EnumValue { |
||||
FOO = 0; |
||||
BAR = 1; |
||||
BAZ = 2; |
||||
QUX = 3; |
||||
} |
||||
|
||||
map<int32, int32> int32_to_int32_field = 1; |
||||
map<int32, string> int32_to_string_field = 2; |
||||
map<int32, bytes> int32_to_bytes_field = 3; |
||||
map<int32, EnumValue> int32_to_enum_field = 4; |
||||
map<int32, MessageValue> int32_to_message_field = 5; |
||||
map<string, int32> string_to_int32_field = 6; |
||||
} |
||||
|
||||
message TestUnknownEnumValue { |
||||
// Wire-compatible with TestMap.int32_to_enum_field so we can test the |
||||
// parsing behavior of TestMap regarding unknown enum values. |
||||
map<int32, int32> int32_to_int32_field = 4; |
||||
} |
@ -0,0 +1,63 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package map_test; |
||||
|
||||
option java_package = "map_test"; |
||||
option java_outer_classname = "MapTestProto"; |
||||
option java_generate_equals_and_hash = true; |
||||
|
||||
message TestMap { |
||||
message MessageValue { |
||||
optional int32 value = 1; |
||||
} |
||||
enum EnumValue { |
||||
FOO = 0; |
||||
BAR = 1; |
||||
BAZ = 2; |
||||
QUX = 3; |
||||
} |
||||
|
||||
map<int32, int32> int32_to_int32_field = 1; |
||||
map<int32, string> int32_to_string_field = 2; |
||||
map<int32, bytes> int32_to_bytes_field = 3; |
||||
map<int32, EnumValue> int32_to_enum_field = 4; |
||||
map<int32, MessageValue> int32_to_message_field = 5; |
||||
map<string, int32> string_to_int32_field = 6; |
||||
} |
||||
|
||||
// Used to test that a nested bulider containing map fields will properly |
||||
// propagate the onChange event and mark its parent dirty when a change |
||||
// is made to a map field. |
||||
message TestOnChangeEventPropagation { |
||||
optional TestMap optional_message = 1; |
||||
} |
@ -0,0 +1,27 @@ |
||||
# Description: |
||||
# An example package that contains nested protos that are imported from |
||||
# __init__.py. See testPackageInitializationImport in reflection_test.py for |
||||
# details. |
||||
|
||||
package( |
||||
default_visibility = ["//net/proto2/python/internal:__pkg__"], |
||||
) |
||||
|
||||
proto_library( |
||||
name = "inner_proto", |
||||
srcs = ["inner.proto"], |
||||
py_api_version = 2, |
||||
) |
||||
|
||||
proto_library( |
||||
name = "outer_proto", |
||||
srcs = ["outer.proto"], |
||||
py_api_version = 2, |
||||
deps = [":inner_proto"], |
||||
) |
||||
|
||||
py_library( |
||||
name = "import_test_package", |
||||
srcs = ["__init__.py"], |
||||
deps = [":outer_proto"], |
||||
) |
@ -0,0 +1,33 @@ |
||||
# 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. |
||||
|
||||
"""Sample module importing a nested proto from itself.""" |
||||
|
||||
from google.protobuf.internal.import_test_package import outer_pb2 as myproto |
@ -0,0 +1,37 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
package google.protobuf.python.internal.import_test_package; |
||||
|
||||
message Inner { |
||||
optional int32 value = 1 [default = 57]; |
||||
} |
@ -0,0 +1,39 @@ |
||||
// 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. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
package google.protobuf.python.internal.import_test_package; |
||||
|
||||
import "google/protobuf/internal/import_test_package/inner.proto"; |
||||
|
||||
message Outer { |
||||
optional Inner inner = 1; |
||||
} |
@ -0,0 +1,77 @@ |
||||
#! /usr/bin/python |
||||
# |
||||
# 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. |
||||
|
||||
"""Tests for google.protobuf.proto_builder.""" |
||||
|
||||
from google.apputils import basetest |
||||
|
||||
from google.protobuf import descriptor_pb2 |
||||
from google.protobuf import descriptor_pool |
||||
from google.protobuf import proto_builder |
||||
from google.protobuf import text_format |
||||
|
||||
|
||||
class ProtoBuilderTest(basetest.TestCase): |
||||
|
||||
def setUp(self): |
||||
self._fields = { |
||||
'foo': descriptor_pb2.FieldDescriptorProto.TYPE_INT64, |
||||
'bar': descriptor_pb2.FieldDescriptorProto.TYPE_STRING, |
||||
} |
||||
|
||||
def testMakeSimpleProtoClass(self): |
||||
"""Test that we can create a proto class.""" |
||||
proto_cls = proto_builder.MakeSimpleProtoClass( |
||||
self._fields, |
||||
full_name='net.proto2.python.public.proto_builder_test.Test') |
||||
proto = proto_cls() |
||||
proto.foo = 12345 |
||||
proto.bar = 'asdf' |
||||
self.assertMultiLineEqual( |
||||
'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto)) |
||||
|
||||
def testMakeSameProtoClassTwice(self): |
||||
"""Test that the DescriptorPool is used.""" |
||||
pool = descriptor_pool.DescriptorPool() |
||||
proto_cls1 = proto_builder.MakeSimpleProtoClass( |
||||
self._fields, |
||||
full_name='net.proto2.python.public.proto_builder_test.Test', |
||||
pool=pool) |
||||
proto_cls2 = proto_builder.MakeSimpleProtoClass( |
||||
self._fields, |
||||
full_name='net.proto2.python.public.proto_builder_test.Test', |
||||
pool=pool) |
||||
self.assertIs(proto_cls1.DESCRIPTOR, proto_cls2.DESCRIPTOR) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
basetest.main() |
@ -0,0 +1,98 @@ |
||||
# 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. |
||||
|
||||
"""Dynamic Protobuf class creator.""" |
||||
|
||||
import hashlib |
||||
import os |
||||
|
||||
from google.protobuf import descriptor_pb2 |
||||
from google.protobuf import message_factory |
||||
|
||||
|
||||
def _GetMessageFromFactory(factory, full_name): |
||||
"""Get a proto class from the MessageFactory by name. |
||||
|
||||
Args: |
||||
factory: a MessageFactory instance. |
||||
full_name: str, the fully qualified name of the proto type. |
||||
Returns: |
||||
a class, for the type identified by full_name. |
||||
Raises: |
||||
KeyError, if the proto is not found in the factory's descriptor pool. |
||||
""" |
||||
proto_descriptor = factory.pool.FindMessageTypeByName(full_name) |
||||
proto_cls = factory.GetPrototype(proto_descriptor) |
||||
return proto_cls |
||||
|
||||
|
||||
def MakeSimpleProtoClass(fields, full_name, pool=None): |
||||
"""Create a Protobuf class whose fields are basic types. |
||||
|
||||
Note: this doesn't validate field names! |
||||
|
||||
Args: |
||||
fields: dict of {name: field_type} mappings for each field in the proto. |
||||
full_name: str, the fully-qualified name of the proto type. |
||||
pool: optional DescriptorPool instance. |
||||
Returns: |
||||
a class, the new protobuf class with a FileDescriptor. |
||||
""" |
||||
factory = message_factory.MessageFactory(pool=pool) |
||||
try: |
||||
proto_cls = _GetMessageFromFactory(factory, full_name) |
||||
return proto_cls |
||||
except KeyError: |
||||
# The factory's DescriptorPool doesn't know about this class yet. |
||||
pass |
||||
|
||||
# Use a consistent file name that is unlikely to conflict with any imported |
||||
# proto files. |
||||
fields_hash = hashlib.sha1() |
||||
for f_name, f_type in sorted(fields.items()): |
||||
fields_hash.update(f_name.encode('utf8')) |
||||
fields_hash.update(str(f_type).encode('utf8')) |
||||
proto_file_name = fields_hash.hexdigest() + '.proto' |
||||
|
||||
package, name = full_name.rsplit('.', 1) |
||||
file_proto = descriptor_pb2.FileDescriptorProto() |
||||
file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name) |
||||
file_proto.package = package |
||||
desc_proto = file_proto.message_type.add() |
||||
desc_proto.name = name |
||||
for f_number, (f_name, f_type) in enumerate(sorted(fields.items()), 1): |
||||
field_proto = desc_proto.field.add() |
||||
field_proto.name = f_name |
||||
field_proto.number = f_number |
||||
field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL |
||||
field_proto.type = f_type |
||||
|
||||
factory.pool.Add(file_proto) |
||||
return _GetMessageFromFactory(factory, full_name) |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue