Down-integrate from google3.
This commit is contained in:
parent
45d03a9771
commit
d61aede89c
@ -45,9 +45,10 @@ __results = []
|
||||
# "benchmarks": [
|
||||
# {
|
||||
# "bytes_per_second": int,
|
||||
# "cpu_time": int,
|
||||
# "cpu_time_ns": double,
|
||||
# "iterations": int,
|
||||
# "name: string,
|
||||
# "time_unit: string,
|
||||
# "real_time_ns: double,
|
||||
# ...
|
||||
# },
|
||||
# ...
|
||||
@ -75,6 +76,36 @@ def __parse_cpp_result(filename):
|
||||
})
|
||||
|
||||
|
||||
# Synthetic benchmark results example:
|
||||
# [
|
||||
# "benchmarks": [
|
||||
# {
|
||||
# "cpu_time_ns": double,
|
||||
# "iterations": int,
|
||||
# "name: string,
|
||||
# "real_time_ns: double,
|
||||
# ...
|
||||
# },
|
||||
# ...
|
||||
# ],
|
||||
# ...
|
||||
# ]
|
||||
def __parse_synthetic_result(filename):
|
||||
if filename == "":
|
||||
return
|
||||
if filename[0] != "/":
|
||||
filename = os.path.dirname(os.path.abspath(__file__)) + "/" + filename
|
||||
with open(filename) as f:
|
||||
results = json.loads(f.read())
|
||||
for benchmark in results["benchmarks"]:
|
||||
__results.append({
|
||||
"language": "cpp",
|
||||
"dataFilename": "",
|
||||
"behavior": "synthetic",
|
||||
"throughput": 10.0**9 / benchmark["cpu_time_ns"]
|
||||
})
|
||||
|
||||
|
||||
# Python results example:
|
||||
# [
|
||||
# [
|
||||
@ -204,7 +235,12 @@ def __parse_go_result(filename):
|
||||
"language": "go"
|
||||
})
|
||||
|
||||
def get_result_from_file(cpp_file="", java_file="", python_file="", go_file=""):
|
||||
|
||||
def get_result_from_file(cpp_file="",
|
||||
java_file="",
|
||||
python_file="",
|
||||
go_file="",
|
||||
synthetic_file=""):
|
||||
results = {}
|
||||
if cpp_file != "":
|
||||
__parse_cpp_result(cpp_file)
|
||||
@ -214,5 +250,7 @@ def get_result_from_file(cpp_file="", java_file="", python_file="", go_file=""):
|
||||
__parse_python_result(python_file)
|
||||
if go_file != "":
|
||||
__parse_go_result(go_file)
|
||||
if synthetic_file != "":
|
||||
__parse_synthetic_result(synthetic_file)
|
||||
|
||||
return __results
|
||||
return __results
|
||||
|
@ -18,14 +18,6 @@ __EOF__
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -e src/Makefile; then
|
||||
cat >&2 << __EOF__
|
||||
Could not find src/Makefile. You must run ./configure (and perhaps
|
||||
./autogen.sh) first.
|
||||
__EOF__
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd src
|
||||
|
||||
declare -a RUNTIME_PROTO_FILES=(\
|
||||
@ -51,7 +43,7 @@ while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--bootstrap_protoc)
|
||||
BOOTSTRAP_PROTOC=$2
|
||||
shift
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
break
|
||||
@ -78,8 +70,8 @@ do
|
||||
PROTOC="./protoc"
|
||||
fi
|
||||
|
||||
$PROTOC --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
|
||||
$PROTOC --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP ${COMPILER_PROTO_FILES[@]}
|
||||
$PROTOC --cpp_out=dllexport_decl=PROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
|
||||
$PROTOC --cpp_out=dllexport_decl=PROTOC_EXPORT:$TMP ${COMPILER_PROTO_FILES[@]}
|
||||
|
||||
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]} ${COMPILER_PROTO_FILES[@]}; do
|
||||
BASE_NAME=${PROTO_FILE%.*}
|
||||
|
@ -44,15 +44,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message} interface which implements
|
||||
* as many methods of that interface as possible in terms of other methods.
|
||||
* A partial implementation of the {@link Message} interface which implements as many methods of
|
||||
* that interface as possible in terms of other methods.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessage
|
||||
// TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
|
||||
extends AbstractMessageLite
|
||||
implements Message {
|
||||
extends AbstractMessageLite implements Message {
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
@ -60,24 +59,21 @@ public abstract class AbstractMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the parent of a Builder that allows the builder to
|
||||
* communicate invalidations back to the parent for use when using nested
|
||||
* builders.
|
||||
* Interface for the parent of a Builder that allows the builder to communicate invalidations back
|
||||
* to the parent for use when using nested builders.
|
||||
*/
|
||||
protected interface BuilderParent {
|
||||
|
||||
/**
|
||||
* A builder becomes dirty whenever a field is modified -- including fields
|
||||
* in nested builders -- and becomes clean when build() is called. Thus,
|
||||
* when a builder becomes dirty, all its parents become dirty as well, and
|
||||
* when it becomes clean, all its children become clean. The dirtiness
|
||||
* state is used to invalidate certain cached values.
|
||||
* <br>
|
||||
* To this end, a builder calls markDirty() on its parent whenever it
|
||||
* transitions from clean to dirty. The parent must propagate this call to
|
||||
* its own parent, unless it was already dirty, in which case the
|
||||
* grandparent must necessarily already be dirty as well. The parent can
|
||||
* only transition back to "clean" after calling build() on all children.
|
||||
* A builder becomes dirty whenever a field is modified -- including fields in nested builders
|
||||
* -- and becomes clean when build() is called. Thus, when a builder becomes dirty, all its
|
||||
* parents become dirty as well, and when it becomes clean, all its children become clean. The
|
||||
* dirtiness state is used to invalidate certain cached values.
|
||||
*
|
||||
* <p>To this end, a builder calls markDirty() on its parent whenever it transitions from clean
|
||||
* to dirty. The parent must propagate this call to its own parent, unless it was already dirty,
|
||||
* in which case the grandparent must necessarily already be dirty as well. The parent can only
|
||||
* transition back to "clean" after calling build() on all children.
|
||||
*/
|
||||
void markDirty();
|
||||
}
|
||||
@ -107,8 +103,7 @@ public abstract class AbstractMessage
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getOneofFieldDescriptor() is not implemented.");
|
||||
throw new UnsupportedOperationException("getOneofFieldDescriptor() is not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,8 +151,8 @@ public abstract class AbstractMessage
|
||||
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
|
||||
return false;
|
||||
}
|
||||
return compareFields(getAllFields(), otherMessage.getAllFields()) &&
|
||||
getUnknownFields().equals(otherMessage.getUnknownFields());
|
||||
return compareFields(getAllFields(), otherMessage.getAllFields())
|
||||
&& getUnknownFields().equals(otherMessage.getUnknownFields());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -182,20 +177,17 @@ public abstract class AbstractMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two bytes fields. The parameters must be either a byte array or a
|
||||
* ByteString object. They can be of different type though.
|
||||
* Compares two bytes fields. The parameters must be either a byte array or a ByteString object.
|
||||
* They can be of different type though.
|
||||
*/
|
||||
private static boolean compareBytes(Object a, Object b) {
|
||||
if (a instanceof byte[] && b instanceof byte[]) {
|
||||
return Arrays.equals((byte[])a, (byte[])b);
|
||||
return Arrays.equals((byte[]) a, (byte[]) b);
|
||||
}
|
||||
return toByteString(a).equals(toByteString(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a list of MapEntry messages into a Map used for equals() and
|
||||
* hashCode().
|
||||
*/
|
||||
/** Converts a list of MapEntry messages into a Map used for equals() and hashCode(). */
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static Map convertMapEntryListToMap(List list) {
|
||||
if (list.isEmpty()) {
|
||||
@ -223,10 +215,7 @@ public abstract class AbstractMessage
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two map fields. The parameters must be a list of MapEntry
|
||||
* messages.
|
||||
*/
|
||||
/** Compares two map fields. The parameters must be a list of MapEntry messages. */
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static boolean compareMapField(Object a, Object b) {
|
||||
Map ma = convertMapEntryListToMap((List) a);
|
||||
@ -235,16 +224,13 @@ public abstract class AbstractMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two set of fields.
|
||||
* This method is used to implement {@link AbstractMessage#equals(Object)}
|
||||
* and {@link AbstractMutableMessage#equals(Object)}. It takes special care
|
||||
* of bytes fields because immutable messages and mutable messages use
|
||||
* different Java type to represent a bytes field and this method should be
|
||||
* able to compare immutable messages, mutable messages and also an immutable
|
||||
* message to a mutable message.
|
||||
* Compares two set of fields. This method is used to implement {@link
|
||||
* AbstractMessage#equals(Object)} and {@link AbstractMutableMessage#equals(Object)}. It takes
|
||||
* special care of bytes fields because immutable messages and mutable messages use different Java
|
||||
* type to represent a bytes field and this method should be able to compare immutable messages,
|
||||
* mutable messages and also an immutable message to a mutable message.
|
||||
*/
|
||||
static boolean compareFields(Map<FieldDescriptor, Object> a,
|
||||
Map<FieldDescriptor, Object> b) {
|
||||
static boolean compareFields(Map<FieldDescriptor, Object> a, Map<FieldDescriptor, Object> b) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
@ -286,10 +272,7 @@ public abstract class AbstractMessage
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash code of a map field. {@code value} must be a list of
|
||||
* MapEntry messages.
|
||||
*/
|
||||
/** Calculates the hash code of a map field. {@code value} must be a list of MapEntry messages. */
|
||||
@SuppressWarnings("unchecked")
|
||||
private static int hashMapField(Object value) {
|
||||
return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value));
|
||||
@ -304,7 +287,7 @@ public abstract class AbstractMessage
|
||||
hash = (37 * hash) + field.getNumber();
|
||||
if (field.isMapField()) {
|
||||
hash = (53 * hash) + hashMapField(value);
|
||||
} else if (field.getType() != FieldDescriptor.Type.ENUM){
|
||||
} else if (field.getType() != FieldDescriptor.Type.ENUM) {
|
||||
hash = (53 * hash) + value.hashCode();
|
||||
} else if (field.isRepeated()) {
|
||||
List<? extends EnumLite> list = (List<? extends EnumLite>) value;
|
||||
@ -317,8 +300,8 @@ public abstract class AbstractMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private helper method for AbstractParser to create
|
||||
* UninitializedMessageException with missing field information.
|
||||
* Package private helper method for AbstractParser to create UninitializedMessageException with
|
||||
* missing field information.
|
||||
*/
|
||||
@Override
|
||||
UninitializedMessageException newUninitializedMessageException() {
|
||||
@ -328,14 +311,12 @@ public abstract class AbstractMessage
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message.Builder} interface which
|
||||
* implements as many methods of that interface as possible in terms of
|
||||
* other methods.
|
||||
* A partial implementation of the {@link Message.Builder} interface which implements as many
|
||||
* methods of that interface as possible in terms of other methods.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static abstract class Builder<BuilderType extends Builder<BuilderType>>
|
||||
extends AbstractMessageLite.Builder
|
||||
implements Message.Builder {
|
||||
public abstract static class Builder<BuilderType extends Builder<BuilderType>>
|
||||
extends AbstractMessageLite.Builder implements Message.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
// Method isn't abstract to bypass Java 1.6 compiler issue:
|
||||
// http://bugs.java.com/view_bug.do?bug_id=6908259
|
||||
@ -353,8 +334,7 @@ public abstract class AbstractMessage
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getOneofFieldDescriptor() is not implemented.");
|
||||
throw new UnsupportedOperationException("getOneofFieldDescriptor() is not implemented.");
|
||||
}
|
||||
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@ -365,8 +345,7 @@ public abstract class AbstractMessage
|
||||
|
||||
@Override
|
||||
public BuilderType clear() {
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
getAllFields().entrySet()) {
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
|
||||
clearField(entry.getKey());
|
||||
}
|
||||
return (BuilderType) this;
|
||||
@ -391,11 +370,11 @@ public abstract class AbstractMessage
|
||||
public BuilderType mergeFrom(final Message other) {
|
||||
return mergeFrom(other, other.getAllFields());
|
||||
}
|
||||
|
||||
|
||||
BuilderType mergeFrom(final Message other, Map<FieldDescriptor, Object> allFields) {
|
||||
if (other.getDescriptorForType() != getDescriptorForType()) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
}
|
||||
|
||||
// Note: We don't attempt to verify that other's fields have valid
|
||||
@ -410,19 +389,21 @@ public abstract class AbstractMessage
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry : allFields.entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
if (field.isRepeated()) {
|
||||
for (final Object element : (List)entry.getValue()) {
|
||||
for (final Object element : (List) entry.getValue()) {
|
||||
addRepeatedField(field, element);
|
||||
}
|
||||
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
final Message existingValue = (Message)getField(field);
|
||||
final Message existingValue = (Message) getField(field);
|
||||
if (existingValue == existingValue.getDefaultInstanceForType()) {
|
||||
setField(field, entry.getValue());
|
||||
} else {
|
||||
setField(field,
|
||||
existingValue.newBuilderForType()
|
||||
.mergeFrom(existingValue)
|
||||
.mergeFrom((Message)entry.getValue())
|
||||
.build());
|
||||
setField(
|
||||
field,
|
||||
existingValue
|
||||
.newBuilderForType()
|
||||
.mergeFrom(existingValue)
|
||||
.mergeFrom((Message) entry.getValue())
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
setField(field, entry.getValue());
|
||||
@ -435,15 +416,13 @@ public abstract class AbstractMessage
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final CodedInputStream input)
|
||||
throws IOException {
|
||||
public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
|
||||
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final CodedInputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
boolean discardUnknown = input.shouldDiscardUnknownFields();
|
||||
final UnknownFieldSet.Builder unknownFields =
|
||||
@ -456,11 +435,8 @@ public abstract class AbstractMessage
|
||||
|
||||
MessageReflection.BuilderAdapter builderAdapter =
|
||||
new MessageReflection.BuilderAdapter(this);
|
||||
if (!MessageReflection.mergeFieldFrom(input, unknownFields,
|
||||
extensionRegistry,
|
||||
getDescriptorForType(),
|
||||
builderAdapter,
|
||||
tag)) {
|
||||
if (!MessageReflection.mergeFieldFrom(
|
||||
input, unknownFields, extensionRegistry, getDescriptorForType(), builderAdapter, tag)) {
|
||||
// end group tag
|
||||
break;
|
||||
}
|
||||
@ -474,9 +450,7 @@ public abstract class AbstractMessage
|
||||
@Override
|
||||
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
|
||||
setUnknownFields(
|
||||
UnknownFieldSet.newBuilder(getUnknownFields())
|
||||
.mergeFrom(unknownFields)
|
||||
.build());
|
||||
UnknownFieldSet.newBuilder(getUnknownFields()).mergeFrom(unknownFields).build());
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@ -497,36 +471,30 @@ public abstract class AbstractMessage
|
||||
return TextFormat.printToString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an UninitializedMessageException reporting missing fields in
|
||||
* the given message.
|
||||
*/
|
||||
protected static UninitializedMessageException
|
||||
newUninitializedMessageException(Message message) {
|
||||
return new UninitializedMessageException(
|
||||
MessageReflection.findMissingFields(message));
|
||||
/** Construct an UninitializedMessageException reporting missing fields in the given message. */
|
||||
protected static UninitializedMessageException newUninitializedMessageException(
|
||||
Message message) {
|
||||
return new UninitializedMessageException(MessageReflection.findMissingFields(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to support nested builders and called to mark this builder as clean.
|
||||
* Clean builders will propagate the {@link BuilderParent#markDirty()} event
|
||||
* to their parent builders, while dirty builders will not, as their parents
|
||||
* should be dirty already.
|
||||
* Used to support nested builders and called to mark this builder as clean. Clean builders will
|
||||
* propagate the {@link BuilderParent#markDirty()} event to their parent builders, while dirty
|
||||
* builders will not, as their parents should be dirty already.
|
||||
*
|
||||
* NOTE: Implementations that don't support nested builders don't need to
|
||||
* override this method.
|
||||
* <p>NOTE: Implementations that don't support nested builders don't need to override this
|
||||
* method.
|
||||
*/
|
||||
void markClean() {
|
||||
throw new IllegalStateException("Should be overridden by subclasses.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to support nested builders and called when this nested builder is
|
||||
* no longer used by its parent builder and should release the reference
|
||||
* to its parent builder.
|
||||
* Used to support nested builders and called when this nested builder is no longer used by its
|
||||
* parent builder and should release the reference to its parent builder.
|
||||
*
|
||||
* NOTE: Implementations that don't support nested builders don't need to
|
||||
* override this method.
|
||||
* <p>NOTE: Implementations that don't support nested builders don't need to override this
|
||||
* method.
|
||||
*/
|
||||
void dispose() {
|
||||
throw new IllegalStateException("Should be overridden by subclasses.");
|
||||
@ -552,73 +520,63 @@ public abstract class AbstractMessage
|
||||
// bug.
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final ByteString data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
final ByteString data, final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data, final int off, final int len)
|
||||
public BuilderType mergeFrom(final byte[] data, final int off, final int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data, final int off, final int len,
|
||||
final byte[] data,
|
||||
final int off,
|
||||
final int len,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final InputStream input)
|
||||
throws IOException {
|
||||
public BuilderType mergeFrom(final InputStream input) throws IOException {
|
||||
return (BuilderType) super.mergeFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
return (BuilderType) super.mergeFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(final InputStream input)
|
||||
throws IOException {
|
||||
public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
|
||||
return super.mergeDelimitedFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
return super.mergeDelimitedFrom(input, extensionRegistry);
|
||||
}
|
||||
}
|
||||
|
@ -41,22 +41,20 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link MessageLite} interface which
|
||||
* implements as many methods of that interface as possible in terms of other
|
||||
* methods.
|
||||
* A partial implementation of the {@link MessageLite} interface which implements as many methods of
|
||||
* that interface as possible in terms of other methods.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessageLite<
|
||||
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
|
||||
BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
|
||||
implements MessageLite {
|
||||
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
|
||||
BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
|
||||
implements MessageLite {
|
||||
protected int memoizedHashCode = 0;
|
||||
@Override
|
||||
public ByteString toByteString() {
|
||||
try {
|
||||
final ByteString.CodedBuilder out =
|
||||
ByteString.newCodedBuilder(getSerializedSize());
|
||||
final ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize());
|
||||
writeTo(out.getCodedOutput());
|
||||
return out.build();
|
||||
} catch (IOException e) {
|
||||
@ -79,10 +77,8 @@ public abstract class AbstractMessageLite<
|
||||
|
||||
@Override
|
||||
public void writeTo(final OutputStream output) throws IOException {
|
||||
final int bufferSize =
|
||||
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
|
||||
final CodedOutputStream codedOutput =
|
||||
CodedOutputStream.newInstance(output, bufferSize);
|
||||
final int bufferSize = CodedOutputStream.computePreferredBufferSize(getSerializedSize());
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
@ -90,10 +86,10 @@ public abstract class AbstractMessageLite<
|
||||
@Override
|
||||
public void writeDelimitedTo(final OutputStream output) throws IOException {
|
||||
final int serialized = getSerializedSize();
|
||||
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
|
||||
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
|
||||
final CodedOutputStream codedOutput =
|
||||
CodedOutputStream.newInstance(output, bufferSize);
|
||||
final int bufferSize =
|
||||
CodedOutputStream.computePreferredBufferSize(
|
||||
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
|
||||
codedOutput.writeRawVarint32(serialized);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
@ -110,16 +106,16 @@ public abstract class AbstractMessageLite<
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Package private helper method for AbstractParser to create
|
||||
* UninitializedMessageException.
|
||||
*/
|
||||
/** Package private helper method for AbstractParser to create UninitializedMessageException. */
|
||||
UninitializedMessageException newUninitializedMessageException() {
|
||||
return new UninitializedMessageException(this);
|
||||
}
|
||||
|
||||
private String getSerializingExceptionMessage(String target) {
|
||||
return "Serializing " + getClass().getName() + " to a " + target
|
||||
return "Serializing "
|
||||
+ getClass().getName()
|
||||
+ " to a "
|
||||
+ target
|
||||
+ " threw an IOException (should never happen).";
|
||||
}
|
||||
|
||||
@ -141,14 +137,13 @@ public abstract class AbstractMessageLite<
|
||||
}
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message.Builder} interface which
|
||||
* implements as many methods of that interface as possible in terms of
|
||||
* other methods.
|
||||
* A partial implementation of the {@link Message.Builder} interface which implements as many
|
||||
* methods of that interface as possible in terms of other methods.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract static class Builder<
|
||||
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
|
||||
BuilderType extends Builder<MessageType, BuilderType>>
|
||||
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
|
||||
BuilderType extends Builder<MessageType, BuilderType>>
|
||||
implements MessageLite.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
@Override
|
||||
@ -204,8 +199,7 @@ public abstract class AbstractMessageLite<
|
||||
public BuilderType mergeFrom(final byte[] data, final int off, final int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
@ -230,8 +224,7 @@ public abstract class AbstractMessageLite<
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input, extensionRegistry);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
@ -260,10 +253,9 @@ public abstract class AbstractMessageLite<
|
||||
}
|
||||
|
||||
/**
|
||||
* An InputStream implementations which reads from some other InputStream
|
||||
* but is limited to a particular number of bytes. Used by
|
||||
* mergeDelimitedFrom(). This is intentionally package-private so that
|
||||
* UnknownFieldSet can share it.
|
||||
* An InputStream implementations which reads from some other InputStream but is limited to a
|
||||
* particular number of bytes. Used by mergeDelimitedFrom(). This is intentionally
|
||||
* package-private so that UnknownFieldSet can share it.
|
||||
*/
|
||||
static final class LimitedInputStream extends FilterInputStream {
|
||||
private int limit;
|
||||
@ -291,8 +283,7 @@ public abstract class AbstractMessageLite<
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] b, final int off, int len)
|
||||
throws IOException {
|
||||
public int read(final byte[] b, final int off, int len) throws IOException {
|
||||
if (limit <= 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -329,8 +320,7 @@ public abstract class AbstractMessageLite<
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
|
||||
return mergeDelimitedFrom(input,
|
||||
ExtensionRegistryLite.getEmptyRegistry());
|
||||
return mergeDelimitedFrom(input, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -347,7 +337,10 @@ public abstract class AbstractMessageLite<
|
||||
protected abstract BuilderType internalMergeFrom(MessageType message);
|
||||
|
||||
private String getReadingExceptionMessage(String target) {
|
||||
return "Reading " + getClass().getName() + " from a " + target
|
||||
return "Reading "
|
||||
+ getClass().getName()
|
||||
+ " from a "
|
||||
+ target
|
||||
+ " threw an IOException (should never happen).";
|
||||
}
|
||||
|
||||
@ -370,12 +363,9 @@ public abstract class AbstractMessageLite<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an UninitializedMessageException reporting missing fields in
|
||||
* the given message.
|
||||
*/
|
||||
protected static UninitializedMessageException
|
||||
newUninitializedMessageException(MessageLite message) {
|
||||
/** Construct an UninitializedMessageException reporting missing fields in the given message. */
|
||||
protected static UninitializedMessageException newUninitializedMessageException(
|
||||
MessageLite message) {
|
||||
return new UninitializedMessageException(message);
|
||||
}
|
||||
|
||||
|
@ -36,23 +36,19 @@ import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Parser} interface which implements
|
||||
* as many methods of that interface as possible in terms of other methods.
|
||||
* A partial implementation of the {@link Parser} interface which implements as many methods of that
|
||||
* interface as possible in terms of other methods.
|
||||
*
|
||||
* Note: This class implements all the convenience methods in the
|
||||
* {@link Parser} interface. See {@link Parser} for related javadocs.
|
||||
* Subclasses need to implement
|
||||
* {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
|
||||
* <p>Note: This class implements all the convenience methods in the {@link Parser} interface. See
|
||||
* {@link Parser} for related javadocs. Subclasses need to implement {@link
|
||||
* Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
|
||||
*
|
||||
* @author liujisi@google.com (Pherl Liu)
|
||||
*/
|
||||
public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
implements Parser<MessageType> {
|
||||
/**
|
||||
* Creates an UninitializedMessageException for MessageType.
|
||||
*/
|
||||
private UninitializedMessageException
|
||||
newUninitializedMessageException(MessageType message) {
|
||||
/** Creates an UninitializedMessageException for MessageType. */
|
||||
private UninitializedMessageException newUninitializedMessageException(MessageType message) {
|
||||
if (message instanceof AbstractMessageLite) {
|
||||
return ((AbstractMessageLite) message).newUninitializedMessageException();
|
||||
}
|
||||
@ -75,8 +71,8 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
return message;
|
||||
}
|
||||
|
||||
private static final ExtensionRegistryLite EMPTY_REGISTRY
|
||||
= ExtensionRegistryLite.getEmptyRegistry();
|
||||
private static final ExtensionRegistryLite EMPTY_REGISTRY =
|
||||
ExtensionRegistryLite.getEmptyRegistry();
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(CodedInputStream input)
|
||||
@ -87,8 +83,7 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
@Override
|
||||
public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(
|
||||
parsePartialFrom(input, extensionRegistry));
|
||||
return checkMessageInitialized(parsePartialFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -193,8 +188,7 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
public MessageType parseFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(
|
||||
parsePartialFrom(data, off, len, extensionRegistry));
|
||||
return checkMessageInitialized(parsePartialFrom(data, off, len, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -235,8 +229,7 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
@Override
|
||||
public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(
|
||||
parsePartialFrom(input, extensionRegistry));
|
||||
return checkMessageInitialized(parsePartialFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -271,8 +264,7 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
@Override
|
||||
public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(
|
||||
parsePartialDelimitedFrom(input, extensionRegistry));
|
||||
return checkMessageInitialized(parsePartialDelimitedFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +31,6 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -39,23 +38,19 @@ import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
|
||||
* methods must check if the list is mutable before proceeding. Subclasses must invoke
|
||||
* {@link #ensureIsMutable()} manually when overriding those methods.
|
||||
* <p>
|
||||
* This implementation assumes all subclasses are array based, supporting random access.
|
||||
* methods must check if the list is mutable before proceeding. Subclasses must invoke {@link
|
||||
* #ensureIsMutable()} manually when overriding those methods.
|
||||
*
|
||||
* <p>This implementation assumes all subclasses are array based, supporting random access.
|
||||
*/
|
||||
abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
|
||||
|
||||
protected static final int DEFAULT_CAPACITY = 10;
|
||||
|
||||
/**
|
||||
* Whether or not this list is modifiable.
|
||||
*/
|
||||
/** Whether or not this list is modifiable. */
|
||||
private boolean isMutable;
|
||||
|
||||
/**
|
||||
* Constructs a mutable list by default.
|
||||
*/
|
||||
/** Constructs a mutable list by default. */
|
||||
AbstractProtobufList() {
|
||||
isMutable = true;
|
||||
}
|
||||
@ -115,7 +110,7 @@ abstract class AbstractProtobufList<E> extends AbstractList<E> implements Protob
|
||||
ensureIsMutable();
|
||||
return super.addAll(c);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
ensureIsMutable();
|
||||
@ -127,47 +122,47 @@ abstract class AbstractProtobufList<E> extends AbstractList<E> implements Protob
|
||||
ensureIsMutable();
|
||||
super.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isModifiable() {
|
||||
return isMutable;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void makeImmutable() {
|
||||
isMutable = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
ensureIsMutable();
|
||||
return super.remove(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
ensureIsMutable();
|
||||
return super.remove(o);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
ensureIsMutable();
|
||||
return super.removeAll(c);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
ensureIsMutable();
|
||||
return super.retainAll(c);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
ensureIsMutable();
|
||||
return super.set(index, element);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are
|
||||
* responsible for invoking this method on mutate operations.
|
||||
|
@ -31,21 +31,21 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
|
||||
* is the blocking equivalent to {@link RpcChannel}.
|
||||
* Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel} is the blocking
|
||||
* equivalent to {@link RpcChannel}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
* @author cpovirk@google.com Chris Povirk
|
||||
*/
|
||||
public interface BlockingRpcChannel {
|
||||
/**
|
||||
* Call the given method of the remote service and blocks until it returns.
|
||||
* {@code callBlockingMethod()} is the blocking equivalent to
|
||||
* {@link RpcChannel#callMethod}.
|
||||
* Call the given method of the remote service and blocks until it returns. {@code
|
||||
* callBlockingMethod()} is the blocking equivalent to {@link RpcChannel#callMethod}.
|
||||
*/
|
||||
Message callBlockingMethod(
|
||||
Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype) throws ServiceException;
|
||||
Message responsePrototype)
|
||||
throws ServiceException;
|
||||
}
|
||||
|
@ -37,28 +37,21 @@ package com.google.protobuf;
|
||||
* @author cpovirk@google.com Chris Povirk
|
||||
*/
|
||||
public interface BlockingService {
|
||||
/**
|
||||
* Equivalent to {@link Service#getDescriptorForType}.
|
||||
*/
|
||||
/** Equivalent to {@link Service#getDescriptorForType}. */
|
||||
Descriptors.ServiceDescriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#callMethod}, except that
|
||||
* {@code callBlockingMethod()} returns the result of the RPC or throws a
|
||||
* {@link ServiceException} if there is a failure, rather than passing the
|
||||
* information to a callback.
|
||||
* Equivalent to {@link Service#callMethod}, except that {@code callBlockingMethod()} returns the
|
||||
* result of the RPC or throws a {@link ServiceException} if there is a failure, rather than
|
||||
* passing the information to a callback.
|
||||
*/
|
||||
Message callBlockingMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request) throws ServiceException;
|
||||
Message callBlockingMethod(
|
||||
Descriptors.MethodDescriptor method, RpcController controller, Message request)
|
||||
throws ServiceException;
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#getRequestPrototype}.
|
||||
*/
|
||||
/** Equivalent to {@link Service#getRequestPrototype}. */
|
||||
Message getRequestPrototype(Descriptors.MethodDescriptor method);
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#getResponsePrototype}.
|
||||
*/
|
||||
/** Equivalent to {@link Service#getResponsePrototype}. */
|
||||
Message getResponsePrototype(Descriptors.MethodDescriptor method);
|
||||
}
|
||||
|
@ -42,11 +42,11 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class BooleanArrayList
|
||||
extends AbstractProtobufList<Boolean>
|
||||
final class BooleanArrayList extends AbstractProtobufList<Boolean>
|
||||
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -55,9 +55,7 @@ final class BooleanArrayList
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing store for the list.
|
||||
*/
|
||||
/** The backing store for the list. */
|
||||
private boolean[] array;
|
||||
|
||||
/**
|
||||
@ -66,16 +64,14 @@ final class BooleanArrayList
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code BooleanArrayList} with default capacity.
|
||||
*/
|
||||
/** Constructs a new mutable {@code BooleanArrayList} with default capacity. */
|
||||
BooleanArrayList() {
|
||||
this(new boolean[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code BooleanArrayList}
|
||||
* containing the same elements as {@code other}.
|
||||
* Constructs a new mutable {@code BooleanArrayList} containing the same elements as {@code
|
||||
* other}.
|
||||
*/
|
||||
private BooleanArrayList(boolean[] other, int size) {
|
||||
array = other;
|
||||
@ -169,17 +165,13 @@ final class BooleanArrayList
|
||||
addBoolean(index, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addBoolean(boolean element) {
|
||||
addBoolean(size, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element. */
|
||||
private void addBoolean(int index, boolean element) {
|
||||
ensureIsMutable();
|
||||
if (index < 0 || index > size) {
|
||||
|
@ -40,45 +40,40 @@ import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
/**
|
||||
* Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s.
|
||||
*/
|
||||
/** Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s. */
|
||||
final class ByteBufferWriter {
|
||||
private ByteBufferWriter() {}
|
||||
|
||||
/**
|
||||
* Minimum size for a cached buffer. This prevents us from allocating buffers that are too
|
||||
* small to be easily reused.
|
||||
* Minimum size for a cached buffer. This prevents us from allocating buffers that are too small
|
||||
* to be easily reused.
|
||||
*/
|
||||
// TODO(nathanmittler): tune this property or allow configuration?
|
||||
private static final int MIN_CACHED_BUFFER_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Maximum size for a cached buffer. If a larger buffer is required, it will be allocated
|
||||
* but not cached.
|
||||
* Maximum size for a cached buffer. If a larger buffer is required, it will be allocated but not
|
||||
* cached.
|
||||
*/
|
||||
// TODO(nathanmittler): tune this property or allow configuration?
|
||||
private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
|
||||
|
||||
/**
|
||||
* The fraction of the requested buffer size under which the buffer will be reallocated.
|
||||
*/
|
||||
/** The fraction of the requested buffer size under which the buffer will be reallocated. */
|
||||
// TODO(nathanmittler): tune this property or allow configuration?
|
||||
private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
|
||||
|
||||
/**
|
||||
* Keeping a soft reference to a thread-local buffer. This buffer is used for writing a
|
||||
* {@link ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available.
|
||||
* Using a "soft" reference since VMs may keep this reference around longer than "weak"
|
||||
* (e.g. HotSpot will maintain soft references until memory pressure warrants collection).
|
||||
* Keeping a soft reference to a thread-local buffer. This buffer is used for writing a {@link
|
||||
* ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available. Using a
|
||||
* "soft" reference since VMs may keep this reference around longer than "weak" (e.g. HotSpot will
|
||||
* maintain soft references until memory pressure warrants collection).
|
||||
*/
|
||||
private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
|
||||
new ThreadLocal<SoftReference<byte[]>>();
|
||||
|
||||
/**
|
||||
* This is a hack for GAE, where {@code FileOutputStream} is unavailable.
|
||||
*/
|
||||
/** This is a hack for GAE, where {@code FileOutputStream} is unavailable. */
|
||||
private static final Class<?> FILE_OUTPUT_STREAM_CLASS = safeGetClass("java.io.FileOutputStream");
|
||||
|
||||
private static final long CHANNEL_FIELD_OFFSET = getChannelFieldOffset(FILE_OUTPUT_STREAM_CLASS);
|
||||
|
||||
/**
|
||||
@ -100,7 +95,7 @@ final class ByteBufferWriter {
|
||||
// Optimized write for array-backed buffers.
|
||||
// Note that we're taking the risk that a malicious OutputStream could modify the array.
|
||||
output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
|
||||
} else if (!writeToChannel(buffer, output)){
|
||||
} else if (!writeToChannel(buffer, output)) {
|
||||
// Read all of the data from the buffer to an array.
|
||||
// TODO(nathanmittler): Consider performance improvements for other "known" stream types.
|
||||
final byte[] array = getOrCreateBuffer(buffer.remaining());
|
||||
@ -171,6 +166,7 @@ final class ByteBufferWriter {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getChannelFieldOffset(Class<?> clazz) {
|
||||
try {
|
||||
if (clazz != null && UnsafeUtil.hasUnsafeArrayOperations()) {
|
||||
|
@ -37,9 +37,9 @@ import java.nio.ByteBuffer;
|
||||
* An output target for raw bytes. This interface provides semantics that support two types of
|
||||
* writing:
|
||||
*
|
||||
* <p><b>Traditional write operations:</b>
|
||||
* (as defined by {@link java.io.OutputStream}) where the target method is responsible for either
|
||||
* copying the data or completing the write before returning from the method call.
|
||||
* <p><b>Traditional write operations:</b> (as defined by {@link java.io.OutputStream}) where the
|
||||
* target method is responsible for either copying the data or completing the write before returning
|
||||
* from the method call.
|
||||
*
|
||||
* <p><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
|
||||
* provided buffer and it can therefore be considered immutable. The target method is free to
|
||||
@ -57,9 +57,9 @@ public abstract class ByteOutput {
|
||||
public abstract void write(byte value) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
|
||||
* not be processed prior to the return of this method call, since {@code value} may be
|
||||
* reused/altered by the caller.
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will not be
|
||||
* processed prior to the return of this method call, since {@code value} may be reused/altered by
|
||||
* the caller.
|
||||
*
|
||||
* <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
|
||||
* programming error and will lead to data corruption which will be difficult to debug.
|
||||
@ -87,15 +87,15 @@ public abstract class ByteOutput {
|
||||
public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
|
||||
* not be processed prior to the return of this method call, since {@code value} may be
|
||||
* reused/altered by the caller.
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will not be
|
||||
* processed prior to the return of this method call, since {@code value} may be reused/altered by
|
||||
* the caller.
|
||||
*
|
||||
* <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
|
||||
* programming error and will lead to data corruption which will be difficult to debug.
|
||||
*
|
||||
* @param value the bytes to be written. Upon returning from this call, the {@code position} of
|
||||
* this buffer will be set to the {@code limit}
|
||||
* this buffer will be set to the {@code limit}
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
public abstract void write(ByteBuffer value) throws IOException;
|
||||
@ -109,7 +109,7 @@ public abstract class ByteOutput {
|
||||
* programming error and will lead to data corruption which will be difficult to debug.
|
||||
*
|
||||
* @param value the bytes to be written. Upon returning from this call, the {@code position} of
|
||||
* this buffer will be set to the {@code limit}
|
||||
* this buffer will be set to the {@code limit}
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
public abstract void writeLazy(ByteBuffer value) throws IOException;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -77,8 +77,11 @@ public abstract class CodedInputStream {
|
||||
return newInstance(input, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/** Create a new CodedInputStream wrapping the given InputStream. */
|
||||
static CodedInputStream newInstance(final InputStream input, int bufferSize) {
|
||||
/** Create a new CodedInputStream wrapping the given InputStream, with a specified buffer size. */
|
||||
public static CodedInputStream newInstance(final InputStream input, int bufferSize) {
|
||||
if (bufferSize <= 0) {
|
||||
throw new IllegalArgumentException("bufferSize must be > 0");
|
||||
}
|
||||
if (input == null) {
|
||||
// TODO(nathanmittler): Ideally we should throw here. This is done for backward compatibility.
|
||||
return newInstance(EMPTY_BYTE_ARRAY);
|
||||
@ -130,7 +133,7 @@ public abstract class CodedInputStream {
|
||||
|
||||
/** Create a new CodedInputStream wrapping the given byte array slice. */
|
||||
public static CodedInputStream newInstance(final byte[] buf, final int off, final int len) {
|
||||
return newInstance(buf, off, len, false /* bufferIsImmutable */);
|
||||
return newInstance(buf, off, len, /* bufferIsImmutable= */ false);
|
||||
}
|
||||
|
||||
/** Create a new CodedInputStream wrapping the given byte array slice. */
|
||||
@ -166,7 +169,7 @@ public abstract class CodedInputStream {
|
||||
* trying to alter the ByteBuffer's status.
|
||||
*/
|
||||
public static CodedInputStream newInstance(ByteBuffer buf) {
|
||||
return newInstance(buf, false /* bufferIsImmutable */);
|
||||
return newInstance(buf, /* bufferIsImmutable= */ false);
|
||||
}
|
||||
|
||||
/** Create a new CodedInputStream wrapping the given buffer. */
|
||||
@ -410,7 +413,6 @@ public abstract class CodedInputStream {
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
|
||||
private boolean shouldDiscardUnknownFields = false;
|
||||
|
||||
/**
|
||||
|
@ -47,12 +47,11 @@ import java.util.logging.Logger;
|
||||
/**
|
||||
* Encodes and writes protocol message fields.
|
||||
*
|
||||
* <p>This class contains two kinds of methods: methods that write specific
|
||||
* protocol message constructs and field types (e.g. {@link #writeTag} and
|
||||
* {@link #writeInt32}) and methods that write low-level values (e.g.
|
||||
* {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
|
||||
* writing encoded protocol messages, you should use the former methods, but if
|
||||
* you are writing some other format of your own design, use the latter.
|
||||
* <p>This class contains two kinds of methods: methods that write specific protocol message
|
||||
* constructs and field types (e.g. {@link #writeTag} and {@link #writeInt32}) and methods that
|
||||
* write low-level values (e.g. {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
|
||||
* writing encoded protocol messages, you should use the former methods, but if you are writing some
|
||||
* other format of your own design, use the latter.
|
||||
*
|
||||
* <p>This class is totally unsynchronized.
|
||||
*/
|
||||
@ -60,23 +59,17 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
|
||||
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
|
||||
/** @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. */
|
||||
@Deprecated public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
|
||||
|
||||
/**
|
||||
* The buffer size used in {@link #newInstance(OutputStream)}.
|
||||
*/
|
||||
/** The buffer size used in {@link #newInstance(OutputStream)}. */
|
||||
public static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Returns the buffer size to efficiently write dataLength bytes to this
|
||||
* CodedOutputStream. Used by AbstractMessageLite.
|
||||
* Returns the buffer size to efficiently write dataLength bytes to this CodedOutputStream. Used
|
||||
* by AbstractMessageLite.
|
||||
*
|
||||
* @return the buffer size to efficiently write dataLength bytes to this
|
||||
* CodedOutputStream.
|
||||
* @return the buffer size to efficiently write dataLength bytes to this CodedOutputStream.
|
||||
*/
|
||||
static int computePreferredBufferSize(int dataLength) {
|
||||
if (dataLength > DEFAULT_BUFFER_SIZE) {
|
||||
@ -88,9 +81,9 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
/**
|
||||
* Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}.
|
||||
*
|
||||
* <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
|
||||
* modify the provided byte arrays. Doing so may result in corrupted data, which would be
|
||||
* difficult to debug.
|
||||
* <p>NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or modify
|
||||
* the provided byte arrays. Doing so may result in corrupted data, which would be difficult to
|
||||
* debug.
|
||||
*/
|
||||
public static CodedOutputStream newInstance(final OutputStream output) {
|
||||
return newInstance(output, DEFAULT_BUFFER_SIZE);
|
||||
@ -100,30 +93,28 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
* Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given
|
||||
* buffer size.
|
||||
*
|
||||
* <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
|
||||
* modify the provided byte arrays. Doing so may result in corrupted data, which would be
|
||||
* difficult to debug.
|
||||
* <p>NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or modify
|
||||
* the provided byte arrays. Doing so may result in corrupted data, which would be difficult to
|
||||
* debug.
|
||||
*/
|
||||
public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) {
|
||||
return new OutputStreamEncoder(output, bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code CodedOutputStream} that writes directly to the given
|
||||
* byte array. If more bytes are written than fit in the array,
|
||||
* {@link OutOfSpaceException} will be thrown. Writing directly to a flat
|
||||
* array is faster than writing to an {@code OutputStream}. See also
|
||||
* {@link ByteString#newCodedBuilder}.
|
||||
* Create a new {@code CodedOutputStream} that writes directly to the given byte array. If more
|
||||
* bytes are written than fit in the array, {@link OutOfSpaceException} will be thrown. Writing
|
||||
* directly to a flat array is faster than writing to an {@code OutputStream}. See also {@link
|
||||
* ByteString#newCodedBuilder}.
|
||||
*/
|
||||
public static CodedOutputStream newInstance(final byte[] flatArray) {
|
||||
return newInstance(flatArray, 0, flatArray.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code CodedOutputStream} that writes directly to the given
|
||||
* byte array slice. If more bytes are written than fit in the slice,
|
||||
* {@link OutOfSpaceException} will be thrown. Writing directly to a flat
|
||||
* array is faster than writing to an {@code OutputStream}. See also
|
||||
* Create a new {@code CodedOutputStream} that writes directly to the given byte array slice. If
|
||||
* more bytes are written than fit in the slice, {@link OutOfSpaceException} will be thrown.
|
||||
* Writing directly to a flat array is faster than writing to an {@code OutputStream}. See also
|
||||
* {@link ByteString#newCodedBuilder}.
|
||||
*/
|
||||
public static CodedOutputStream newInstance(
|
||||
@ -162,9 +153,9 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
* implies:
|
||||
*
|
||||
* <ul>
|
||||
* <li>repeated serialization of a message will return the same bytes
|
||||
* <li>different processes of the same binary (which may be executing on different machines) will
|
||||
* serialize equal messages to the same bytes.
|
||||
* <li>repeated serialization of a message will return the same bytes
|
||||
* <li>different processes of the same binary (which may be executing on different machines)
|
||||
* will serialize equal messages to the same bytes.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable
|
||||
@ -173,14 +164,14 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
* their own canonicalization specification and implement the serializer using reflection APIs
|
||||
* rather than relying on this API.
|
||||
*
|
||||
* <p> Once set, the serializer will: (Note this is an implementation detail and may subject to
|
||||
* <p>Once set, the serializer will: (Note this is an implementation detail and may subject to
|
||||
* change in the future)
|
||||
*
|
||||
* <ul>
|
||||
* <li> sort map entries by keys in lexicographical order or numerical order. Note: For string
|
||||
* keys, the order is based on comparing the Unicode value of each character in the strings.
|
||||
* The order may be different from the deterministic serialization in other languages where
|
||||
* maps are sorted on the lexicographical order of the UTF8 encoded keys.
|
||||
* <li>sort map entries by keys in lexicographical order or numerical order. Note: For string
|
||||
* keys, the order is based on comparing the Unicode value of each character in the strings.
|
||||
* The order may be different from the deterministic serialization in other languages where
|
||||
* maps are sorted on the lexicographical order of the UTF8 encoded keys.
|
||||
* </ul>
|
||||
*/
|
||||
public void useDeterministicSerialization() {
|
||||
@ -190,31 +181,32 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
boolean isSerializationDeterministic() {
|
||||
return serializationDeterministic;
|
||||
}
|
||||
|
||||
private boolean serializationDeterministic;
|
||||
|
||||
/**
|
||||
* Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
|
||||
*
|
||||
* @deprecated the size parameter is no longer used since use of an internal buffer is useless
|
||||
* (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
|
||||
* instead.
|
||||
* (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
|
||||
@SuppressWarnings("unused") int unused) {
|
||||
public static CodedOutputStream newInstance(
|
||||
ByteBuffer byteBuffer, @SuppressWarnings("unused") int unused) {
|
||||
return newInstance(byteBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}.
|
||||
*
|
||||
* <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
|
||||
* so may result in corrupted data, which would be difficult to debug.
|
||||
* <p>NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing so
|
||||
* may result in corrupted data, which would be difficult to debug.
|
||||
*
|
||||
* @param byteOutput the output target for encoded bytes.
|
||||
* @param bufferSize the size of the internal scratch buffer to be used for string encoding.
|
||||
* Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
|
||||
* string.
|
||||
* Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
|
||||
* string.
|
||||
*/
|
||||
static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) {
|
||||
if (bufferSize < 0) {
|
||||
@ -225,8 +217,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
// Disallow construction outside of this class.
|
||||
private CodedOutputStream() {
|
||||
}
|
||||
private CodedOutputStream() {}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
@ -294,8 +285,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write an enum field, including tag, to the stream. The provided value is the numeric
|
||||
* value used to represent the enum value on the wire (not the enum ordinal value).
|
||||
* Write an enum field, including tag, to the stream. The provided value is the numeric value used
|
||||
* to represent the enum value on the wire (not the enum ordinal value).
|
||||
*/
|
||||
public final void writeEnum(final int fieldNumber, final int value) throws IOException {
|
||||
writeInt32(fieldNumber, value);
|
||||
@ -319,21 +310,17 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Write a {@code bytes} field, including tag, to the stream.
|
||||
* This method will write all content of the ByteBuffer regardless of the
|
||||
* current position and limit (i.e., the number of bytes to be written is
|
||||
* value.capacity(), not value.remaining()). Furthermore, this method doesn't
|
||||
* alter the state of the passed-in ByteBuffer. Its position, limit, mark,
|
||||
* etc. will remain unchanged. If you only want to write the remaining bytes
|
||||
* of a ByteBuffer, you can call
|
||||
* {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
|
||||
* Write a {@code bytes} field, including tag, to the stream. This method will write all content
|
||||
* of the ByteBuffer regardless of the current position and limit (i.e., the number of bytes to be
|
||||
* written is value.capacity(), not value.remaining()). Furthermore, this method doesn't alter the
|
||||
* state of the passed-in ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If
|
||||
* you only want to write the remaining bytes of a ByteBuffer, you can call {@code
|
||||
* writeByteBuffer(fieldNumber, byteBuffer.slice())}.
|
||||
*/
|
||||
// Abstract to avoid overhead of additional virtual method calls.
|
||||
public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a single byte.
|
||||
*/
|
||||
/** Write a single byte. */
|
||||
public final void writeRawByte(final byte value) throws IOException {
|
||||
write(value);
|
||||
}
|
||||
@ -348,9 +335,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
write(value, 0, value.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write part of an array of bytes.
|
||||
*/
|
||||
/** Write part of an array of bytes. */
|
||||
public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException {
|
||||
write(value, offset, length);
|
||||
}
|
||||
@ -361,13 +346,11 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a ByteBuffer. This method will write all content of the ByteBuffer
|
||||
* regardless of the current position and limit (i.e., the number of bytes
|
||||
* to be written is value.capacity(), not value.remaining()). Furthermore,
|
||||
* this method doesn't alter the state of the passed-in ByteBuffer. Its
|
||||
* position, limit, mark, etc. will remain unchanged. If you only want to
|
||||
* write the remaining bytes of a ByteBuffer, you can call
|
||||
* {@code writeRawBytes(byteBuffer.slice())}.
|
||||
* Write a ByteBuffer. This method will write all content of the ByteBuffer regardless of the
|
||||
* current position and limit (i.e., the number of bytes to be written is value.capacity(), not
|
||||
* value.remaining()). Furthermore, this method doesn't alter the state of the passed-in
|
||||
* ByteBuffer. Its position, limit, mark, etc. will remain unchanged. If you only want to write
|
||||
* the remaining bytes of a ByteBuffer, you can call {@code writeRawBytes(byteBuffer.slice())}.
|
||||
*/
|
||||
// Abstract to avoid overhead of additional virtual method calls.
|
||||
public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
|
||||
@ -379,16 +362,16 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
|
||||
/**
|
||||
* Write a MessageSet extension field to the stream. For historical reasons,
|
||||
* the wire format differs from normal fields.
|
||||
* Write a MessageSet extension field to the stream. For historical reasons, the wire format
|
||||
* differs from normal fields.
|
||||
*/
|
||||
// Abstract to avoid overhead of additional virtual method calls.
|
||||
public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Write an unparsed MessageSet extension field to the stream. For
|
||||
* historical reasons, the wire format differs from normal fields.
|
||||
* Write an unparsed MessageSet extension field to the stream. For historical reasons, the wire
|
||||
* format differs from normal fields.
|
||||
*/
|
||||
// Abstract to avoid overhead of additional virtual method calls.
|
||||
public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
|
||||
@ -457,8 +440,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum field to the stream. The provided value is the numeric
|
||||
* value used to represent the enum value on the wire (not the enum ordinal value).
|
||||
* Write an enum field to the stream. The provided value is the numeric value used to represent
|
||||
* the enum value on the wire (not the enum ordinal value).
|
||||
*/
|
||||
public final void writeEnumNoTag(final int value) throws IOException {
|
||||
writeInt32NoTag(value);
|
||||
@ -483,7 +466,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
|
||||
|
||||
|
||||
//=================================================================
|
||||
// =================================================================
|
||||
|
||||
@ExperimentalApi
|
||||
@Override
|
||||
@ -508,161 +491,160 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code int32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code int32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeInt32Size(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code uint32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code uint32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeUInt32Size(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sint32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code sint32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeSInt32Size(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code fixed32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code fixed32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeFixed32Size(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sfixed32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code sfixed32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeSFixed32Size(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code int64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code int64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeInt64Size(final int fieldNumber, final long value) {
|
||||
return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code uint64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code uint64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeUInt64Size(final int fieldNumber, final long value) {
|
||||
return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sint64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code sint64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeSInt64Size(final int fieldNumber, final long value) {
|
||||
return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code fixed64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code fixed64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeFixed64Size(final int fieldNumber, final long value) {
|
||||
return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sfixed64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code sfixed64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeSFixed64Size(final int fieldNumber, final long value) {
|
||||
return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code float} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code float} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeFloatSize(final int fieldNumber, final float value) {
|
||||
return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code double} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code double} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeDoubleSize(final int fieldNumber, final double value) {
|
||||
return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bool} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code bool} field, including tag.
|
||||
*/
|
||||
public static int computeBoolSize(final int fieldNumber, final boolean value) {
|
||||
return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* enum field, including tag. The provided value is the numeric
|
||||
* value used to represent the enum value on the wire (not the enum ordinal value).
|
||||
* Compute the number of bytes that would be needed to encode an enum field, including tag. The
|
||||
* provided value is the numeric value used to represent the enum value on the wire (not the enum
|
||||
* ordinal value).
|
||||
*/
|
||||
public static int computeEnumSize(final int fieldNumber, final int value) {
|
||||
return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code string} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code string} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeStringSize(final int fieldNumber, final String value) {
|
||||
return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code bytes} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeBytesSize(final int fieldNumber, final ByteString value) {
|
||||
return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code bytes} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeByteArraySize(final int fieldNumber, final byte[] value) {
|
||||
return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code bytes} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) {
|
||||
return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* embedded message in lazy field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an embedded message in lazy field,
|
||||
* including tag.
|
||||
*/
|
||||
public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) {
|
||||
return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* embedded message field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an embedded message field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeMessageSize(final int fieldNumber, final MessageLite value) {
|
||||
return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
|
||||
@ -670,9 +652,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* MessageSet extension to the stream. For historical reasons,
|
||||
* the wire format differs from normal fields.
|
||||
* Compute the number of bytes that would be needed to encode a MessageSet extension to the
|
||||
* stream. For historical reasons, the wire format differs from normal fields.
|
||||
*/
|
||||
public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) {
|
||||
return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
|
||||
@ -681,9 +662,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* unparsed MessageSet extension field to the stream. For
|
||||
* historical reasons, the wire format differs from normal fields.
|
||||
* Compute the number of bytes that would be needed to encode an unparsed MessageSet extension
|
||||
* field to the stream. For historical reasons, the wire format differs from normal fields.
|
||||
*/
|
||||
public static int computeRawMessageSetExtensionSize(
|
||||
final int fieldNumber, final ByteString value) {
|
||||
@ -693,9 +673,9 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* lazily parsed MessageSet extension field to the stream. For
|
||||
* historical reasons, the wire format differs from normal fields.
|
||||
* Compute the number of bytes that would be needed to encode an lazily parsed MessageSet
|
||||
* extension field to the stream. For historical reasons, the wire format differs from normal
|
||||
* fields.
|
||||
*/
|
||||
public static int computeLazyFieldMessageSetExtensionSize(
|
||||
final int fieldNumber, final LazyFieldLite value) {
|
||||
@ -712,8 +692,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code int32} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code int32} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeInt32SizeNoTag(final int value) {
|
||||
if (value >= 0) {
|
||||
@ -724,12 +704,9 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code uint32} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code uint32} field. */
|
||||
public static int computeUInt32SizeNoTag(final int value) {
|
||||
if ((value & (~0 << 7)) == 0) {
|
||||
if ((value & (~0 << 7)) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((value & (~0 << 14)) == 0) {
|
||||
@ -744,41 +721,32 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sint32} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode an {@code sint32} field. */
|
||||
public static int computeSInt32SizeNoTag(final int value) {
|
||||
return computeUInt32SizeNoTag(encodeZigZag32(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code fixed32} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code fixed32} field. */
|
||||
public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
|
||||
return FIXED32_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sfixed32} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode an {@code sfixed32} field. */
|
||||
public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
|
||||
return FIXED32_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code int64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode an {@code int64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeInt64SizeNoTag(final long value) {
|
||||
return computeUInt64SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code uint64} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code uint64} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeUInt64SizeNoTag(long value) {
|
||||
// handle two popular special cases up front ...
|
||||
@ -791,10 +759,12 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
// ... leaving us with 8 remaining, which we can divide and conquer
|
||||
int n = 2;
|
||||
if ((value & (~0L << 35)) != 0L) {
|
||||
n += 4; value >>>= 28;
|
||||
n += 4;
|
||||
value >>>= 28;
|
||||
}
|
||||
if ((value & (~0L << 21)) != 0L) {
|
||||
n += 2; value >>>= 14;
|
||||
n += 2;
|
||||
value >>>= 14;
|
||||
}
|
||||
if ((value & (~0L << 14)) != 0L) {
|
||||
n += 1;
|
||||
@ -802,67 +772,51 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sint64} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode an {@code sint64} field. */
|
||||
public static int computeSInt64SizeNoTag(final long value) {
|
||||
return computeUInt64SizeNoTag(encodeZigZag64(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code fixed64} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code fixed64} field. */
|
||||
public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
|
||||
return FIXED64_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an
|
||||
* {@code sfixed64} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode an {@code sfixed64} field. */
|
||||
public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
|
||||
return FIXED64_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code float} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code float} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
|
||||
return FIXED32_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code double} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code double} field, including
|
||||
* tag.
|
||||
*/
|
||||
public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
|
||||
return FIXED64_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bool} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code bool} field. */
|
||||
public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an enum field.
|
||||
* The provided value is the numeric value used to represent the enum value on the wire
|
||||
* (not the enum ordinal value).
|
||||
* Compute the number of bytes that would be needed to encode an enum field. The provided value is
|
||||
* the numeric value used to represent the enum value on the wire (not the enum ordinal value).
|
||||
*/
|
||||
public static int computeEnumSizeNoTag(final int value) {
|
||||
return computeInt32SizeNoTag(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code string} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code string} field. */
|
||||
public static int computeStringSizeNoTag(final String value) {
|
||||
int length;
|
||||
try {
|
||||
@ -877,41 +831,29 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an embedded
|
||||
* message stored in lazy field.
|
||||
* Compute the number of bytes that would be needed to encode an embedded message stored in lazy
|
||||
* field.
|
||||
*/
|
||||
public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
|
||||
return computeLengthDelimitedFieldSize(value.getSerializedSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
|
||||
public static int computeBytesSizeNoTag(final ByteString value) {
|
||||
return computeLengthDelimitedFieldSize(value.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
|
||||
public static int computeByteArraySizeNoTag(final byte[] value) {
|
||||
return computeLengthDelimitedFieldSize(value.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code bytes} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code bytes} field. */
|
||||
public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
|
||||
return computeLengthDelimitedFieldSize(value.capacity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode an embedded
|
||||
* message field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode an embedded message field. */
|
||||
public static int computeMessageSizeNoTag(final MessageLite value) {
|
||||
return computeLengthDelimitedFieldSize(value.getSerializedSize());
|
||||
}
|
||||
@ -922,14 +864,13 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
* Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into values that can be
|
||||
* efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits
|
||||
* to be varint encoded, thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n A signed 32-bit integer.
|
||||
* @return An unsigned 32-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return An unsigned 32-bit integer, stored in a signed int because Java has no explicit
|
||||
* unsigned support.
|
||||
*/
|
||||
public static int encodeZigZag32(final int n) {
|
||||
// Note: the right-shift must be arithmetic
|
||||
@ -937,14 +878,13 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
* Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be
|
||||
* efficiently encoded with varint. (Otherwise, negative values must be sign-extended to 64 bits
|
||||
* to be varint encoded, thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n A signed 64-bit integer.
|
||||
* @return An unsigned 64-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return An unsigned 64-bit integer, stored in a signed int because Java has no explicit
|
||||
* unsigned support.
|
||||
*/
|
||||
public static long encodeZigZag64(final long n) {
|
||||
// Note: the right-shift must be arithmetic
|
||||
@ -954,23 +894,22 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Flushes the stream and forces any buffered bytes to be written. This
|
||||
* does not flush the underlying OutputStream.
|
||||
* Flushes the stream and forces any buffered bytes to be written. This does not flush the
|
||||
* underlying OutputStream.
|
||||
*/
|
||||
public abstract void flush() throws IOException;
|
||||
|
||||
/**
|
||||
* If writing to a flat array, return the space left in the array.
|
||||
* Otherwise, throws {@code UnsupportedOperationException}.
|
||||
* If writing to a flat array, return the space left in the array. Otherwise, throws {@code
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
public abstract int spaceLeft();
|
||||
|
||||
/**
|
||||
* Verifies that {@link #spaceLeft()} returns zero. It's common to create
|
||||
* a byte array that is exactly big enough to hold a message, then write to
|
||||
* it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()}
|
||||
* after writing verifies that the message was actually as big as expected,
|
||||
* which can help catch bugs.
|
||||
* Verifies that {@link #spaceLeft()} returns zero. It's common to create a byte array that is
|
||||
* exactly big enough to hold a message, then write to it with a {@code CodedOutputStream}.
|
||||
* Calling {@code checkNoSpaceLeft()} after writing verifies that the message was actually as big
|
||||
* as expected, which can help catch bugs.
|
||||
*/
|
||||
public final void checkNoSpaceLeft() {
|
||||
if (spaceLeft() != 0) {
|
||||
@ -979,9 +918,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* If you create a CodedOutputStream around a simple flat array, you must
|
||||
* not attempt to write more bytes than the array has space. Otherwise,
|
||||
* this exception will be thrown.
|
||||
* If you create a CodedOutputStream around a simple flat array, you must not attempt to write
|
||||
* more bytes than the array has space. Otherwise, this exception will be thrown.
|
||||
*/
|
||||
public static class OutOfSpaceException extends IOException {
|
||||
private static final long serialVersionUID = -6947486886997889499L;
|
||||
@ -1007,9 +945,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of bytes successfully written to this stream. The
|
||||
* returned value is not guaranteed to be accurate if exceptions have been
|
||||
* found in the middle of writing.
|
||||
* Get the total number of bytes successfully written to this stream. The returned value is not
|
||||
* guaranteed to be accurate if exceptions have been found in the middle of writing.
|
||||
*/
|
||||
public abstract int getTotalBytesWritten();
|
||||
|
||||
@ -1021,8 +958,10 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause)
|
||||
throws IOException {
|
||||
logger.log(Level.WARNING,
|
||||
"Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause);
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!",
|
||||
cause);
|
||||
|
||||
// Unfortunately there does not appear to be any way to tell Java to encode
|
||||
// UTF-8 directly into our buffer, so we have to let it create its own byte
|
||||
@ -1066,8 +1005,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code group} field, including tag.
|
||||
* Compute the number of bytes that would be needed to encode a {@code group} field, including
|
||||
* tag.
|
||||
*
|
||||
* @deprecated groups are deprecated.
|
||||
*/
|
||||
@ -1077,10 +1016,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* {@code group} field.
|
||||
*/
|
||||
/** Compute the number of bytes that would be needed to encode a {@code group} field. */
|
||||
@Deprecated
|
||||
public static int computeGroupSizeNoTag(final MessageLite value) {
|
||||
return value.getSerializedSize();
|
||||
@ -1088,8 +1024,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
|
||||
/**
|
||||
* Encode and write a varint. {@code value} is treated as
|
||||
* unsigned, so it won't be sign-extended if negative.
|
||||
* Encode and write a varint. {@code value} is treated as unsigned, so it won't be sign-extended
|
||||
* if negative.
|
||||
*
|
||||
* @deprecated use {@link #writeUInt32NoTag} instead.
|
||||
*/
|
||||
@ -1109,9 +1045,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a varint.
|
||||
* {@code value} is treated as unsigned, so it won't be sign-extended if
|
||||
* negative.
|
||||
* Compute the number of bytes that would be needed to encode a varint. {@code value} is treated
|
||||
* as unsigned, so it won't be sign-extended if negative.
|
||||
*
|
||||
* @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
|
||||
*/
|
||||
@ -1152,9 +1087,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* A {@link CodedOutputStream} that writes directly to a byte array.
|
||||
*/
|
||||
/** A {@link CodedOutputStream} that writes directly to a byte array. */
|
||||
private static class ArrayEncoder extends CodedOutputStream {
|
||||
private final byte[] buffer;
|
||||
private final int offset;
|
||||
@ -1166,9 +1099,10 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
throw new NullPointerException("buffer");
|
||||
}
|
||||
if ((offset | length | (buffer.length - (offset + length))) < 0) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
|
||||
buffer.length, offset, length));
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
|
||||
buffer.length, offset, length));
|
||||
}
|
||||
this.buffer = buffer;
|
||||
this.offset = offset;
|
||||
@ -1501,15 +1435,17 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
|
||||
* done directly to the underlying array. The buffer position is only updated after a flush.
|
||||
* A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are done
|
||||
* directly to the underlying array. The buffer position is only updated after a flush.
|
||||
*/
|
||||
private static final class HeapNioEncoder extends ArrayEncoder {
|
||||
private final ByteBuffer byteBuffer;
|
||||
private int initialPosition;
|
||||
|
||||
HeapNioEncoder(ByteBuffer byteBuffer) {
|
||||
super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
|
||||
super(
|
||||
byteBuffer.array(),
|
||||
byteBuffer.arrayOffset() + byteBuffer.position(),
|
||||
byteBuffer.remaining());
|
||||
this.byteBuffer = byteBuffer;
|
||||
this.initialPosition = byteBuffer.position();
|
||||
@ -1604,16 +1540,14 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
|
||||
throws IOException {
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeUInt32NoTag(value.capacity());
|
||||
writeRawBytes(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value)
|
||||
throws IOException {
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeMessageNoTag(value);
|
||||
}
|
||||
@ -2186,9 +2120,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for buffered encoders.
|
||||
*/
|
||||
/** Abstract base class for buffered encoders. */
|
||||
private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
|
||||
final byte[] buffer;
|
||||
final int limit;
|
||||
@ -2346,8 +2278,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
|
||||
/**
|
||||
* A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to
|
||||
* support string encoding operations. All other writes are just passed through to the
|
||||
* {@link ByteOutput}.
|
||||
* support string encoding operations. All other writes are just passed through to the {@link
|
||||
* ByteOutput}.
|
||||
*/
|
||||
private static final class ByteOutputEncoder extends AbstractBufferedEncoder {
|
||||
private final ByteOutput out;
|
||||
@ -2433,8 +2365,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
|
||||
throws IOException {
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeUInt32NoTag(value.capacity());
|
||||
writeRawBytes(value);
|
||||
@ -2464,8 +2395,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value)
|
||||
throws IOException {
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeMessageNoTag(value);
|
||||
}
|
||||
@ -2738,8 +2668,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
|
||||
throws IOException {
|
||||
public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeUInt32NoTag(value.capacity());
|
||||
writeRawBytes(value);
|
||||
@ -2769,8 +2698,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value)
|
||||
throws IOException {
|
||||
public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException {
|
||||
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
writeMessageNoTag(value);
|
||||
}
|
||||
@ -2916,8 +2844,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] value, int offset, int length)
|
||||
throws IOException {
|
||||
public void write(byte[] value, int offset, int length) throws IOException {
|
||||
if (limit - position >= length) {
|
||||
// We have room in the current buffer.
|
||||
System.arraycopy(value, offset, buffer, position, length);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,7 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Parsers to discard unknown fields during parsing.
|
||||
*/
|
||||
/** Parsers to discard unknown fields during parsing. */
|
||||
public final class DiscardUnknownFieldsParser {
|
||||
|
||||
/**
|
||||
@ -40,11 +38,12 @@ public final class DiscardUnknownFieldsParser {
|
||||
* parsing.
|
||||
*
|
||||
* <p>Usage example:
|
||||
*
|
||||
* <pre>{@code
|
||||
* private final static Parser<Foo> FOO_PARSER = DiscardUnknownFieldsParser.wrap(Foo.parser());
|
||||
* Foo parseFooDiscardUnknown(ByteBuffer input) throws IOException {
|
||||
* return FOO_PARSER.parseFrom(input);
|
||||
* }
|
||||
* private final static Parser<Foo> FOO_PARSER = DiscardUnknownFieldsParser.wrap(Foo.parser());
|
||||
* Foo parseFooDiscardUnknown(ByteBuffer input) throws IOException {
|
||||
* return FOO_PARSER.parseFrom(input);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Like all other implementations of {@code Parser}, this parser is stateless and thread-safe.
|
||||
|
@ -42,11 +42,11 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class DoubleArrayList
|
||||
extends AbstractProtobufList<Double>
|
||||
final class DoubleArrayList extends AbstractProtobufList<Double>
|
||||
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -55,9 +55,7 @@ final class DoubleArrayList
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing store for the list.
|
||||
*/
|
||||
/** The backing store for the list. */
|
||||
private double[] array;
|
||||
|
||||
/**
|
||||
@ -66,16 +64,13 @@ final class DoubleArrayList
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code DoubleArrayList} with default capacity.
|
||||
*/
|
||||
/** Constructs a new mutable {@code DoubleArrayList} with default capacity. */
|
||||
DoubleArrayList() {
|
||||
this(new double[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code DoubleArrayList}
|
||||
* containing the same elements as {@code other}.
|
||||
* Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
|
||||
*/
|
||||
private DoubleArrayList(double[] other, int size) {
|
||||
array = other;
|
||||
@ -170,17 +165,13 @@ final class DoubleArrayList
|
||||
addDouble(index, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(Double)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Double)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addDouble(double element) {
|
||||
addDouble(size, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(int, Double)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(int, Double)} but more efficient in that it doesn't box the element. */
|
||||
private void addDouble(int index, double element) {
|
||||
ensureIsMutable();
|
||||
if (index < 0 || index > size) {
|
||||
|
@ -43,8 +43,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Message} that can represent arbitrary types,
|
||||
* given a {@link Descriptors.Descriptor}.
|
||||
* An implementation of {@link Message} that can represent arbitrary types, given a {@link
|
||||
* Descriptors.Descriptor}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -56,88 +56,83 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
private int memoizedSize = -1;
|
||||
|
||||
/**
|
||||
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
|
||||
* oneofCases stores the FieldDescriptor for each oneof to indicate
|
||||
* which field is set. Caller should make sure the array is immutable.
|
||||
* Construct a {@code DynamicMessage} using the given {@code FieldSet}. oneofCases stores the
|
||||
* FieldDescriptor for each oneof to indicate which field is set. Caller should make sure the
|
||||
* array is immutable.
|
||||
*
|
||||
* This constructor is package private and will be used in
|
||||
* {@code DynamicMutableMessage} to convert a mutable message to an immutable
|
||||
* message.
|
||||
* <p>This constructor is package private and will be used in {@code DynamicMutableMessage} to
|
||||
* convert a mutable message to an immutable message.
|
||||
*/
|
||||
DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
|
||||
FieldDescriptor[] oneofCases,
|
||||
UnknownFieldSet unknownFields) {
|
||||
DynamicMessage(
|
||||
Descriptor type,
|
||||
FieldSet<FieldDescriptor> fields,
|
||||
FieldDescriptor[] oneofCases,
|
||||
UnknownFieldSet unknownFields) {
|
||||
this.type = type;
|
||||
this.fields = fields;
|
||||
this.oneofCases = oneofCases;
|
||||
this.unknownFields = unknownFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code DynamicMessage} representing the default instance of the
|
||||
* given type.
|
||||
*/
|
||||
/** Get a {@code DynamicMessage} representing the default instance of the given type. */
|
||||
public static DynamicMessage getDefaultInstance(Descriptor type) {
|
||||
int oneofDeclCount = type.toProto().getOneofDeclCount();
|
||||
FieldDescriptor[] oneofCases = new FieldDescriptor[oneofDeclCount];
|
||||
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
|
||||
oneofCases,
|
||||
UnknownFieldSet.getDefaultInstance());
|
||||
return new DynamicMessage(
|
||||
type,
|
||||
FieldSet.<FieldDescriptor>emptySet(),
|
||||
oneofCases,
|
||||
UnknownFieldSet.getDefaultInstance());
|
||||
}
|
||||
|
||||
|
||||
/** Parse a message of the given type from the given input stream. */
|
||||
public static DynamicMessage parseFrom(Descriptor type,
|
||||
CodedInputStream input)
|
||||
throws IOException {
|
||||
public static DynamicMessage parseFrom(Descriptor type, CodedInputStream input)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from the given input stream. */
|
||||
public static DynamicMessage parseFrom(
|
||||
Descriptor type,
|
||||
CodedInputStream input,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
Descriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, ByteString data,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
public static DynamicMessage parseFrom(
|
||||
Descriptor type, ByteString data, ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, byte[] data,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
public static DynamicMessage parseFrom(
|
||||
Descriptor type, byte[] data, ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from {@code input} and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, InputStream input)
|
||||
throws IOException {
|
||||
public static DynamicMessage parseFrom(Descriptor type, InputStream input) throws IOException {
|
||||
return newBuilder(type).mergeFrom(input).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from {@code input} and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, InputStream input,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws IOException {
|
||||
public static DynamicMessage parseFrom(
|
||||
Descriptor type, InputStream input, ExtensionRegistry extensionRegistry) throws IOException {
|
||||
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
@ -147,8 +142,8 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link Message.Builder} for a message of the same type as
|
||||
* {@code prototype}, and initialize it with {@code prototype}'s contents.
|
||||
* Construct a {@link Message.Builder} for a message of the same type as {@code prototype}, and
|
||||
* initialize it with {@code prototype}'s contents.
|
||||
*/
|
||||
public static Builder newBuilder(Message prototype) {
|
||||
return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
|
||||
@ -227,8 +222,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
static boolean isInitialized(Descriptor type,
|
||||
FieldSet<FieldDescriptor> fields) {
|
||||
static boolean isInitialized(Descriptor type, FieldSet<FieldDescriptor> fields) {
|
||||
// Check that all required fields are present.
|
||||
for (final FieldDescriptor field : type.getFields()) {
|
||||
if (field.isRequired()) {
|
||||
@ -298,8 +292,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (IOException e) {
|
||||
throw new InvalidProtocolBufferException(e)
|
||||
.setUnfinishedMessage(builder.buildPartial());
|
||||
throw new InvalidProtocolBufferException(e).setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
@ -309,24 +302,20 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
/** Verifies that the field is a field of this message. */
|
||||
private void verifyContainingType(FieldDescriptor field) {
|
||||
if (field.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"FieldDescriptor does not match message type.");
|
||||
throw new IllegalArgumentException("FieldDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that the oneof is an oneof of this message. */
|
||||
private void verifyOneofContainingType(OneofDescriptor oneof) {
|
||||
if (oneof.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"OneofDescriptor does not match message type.");
|
||||
throw new IllegalArgumentException("OneofDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Builder for {@link DynamicMessage}s.
|
||||
*/
|
||||
/** Builder for {@link DynamicMessage}s. */
|
||||
public static final class Builder extends AbstractMessage.Builder<Builder> {
|
||||
private final Descriptor type;
|
||||
private FieldSet<FieldDescriptor> fields;
|
||||
@ -380,7 +369,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
|
||||
if (otherDynamicMessage.type != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
}
|
||||
ensureIsMutable();
|
||||
fields.mergeFrom(otherDynamicMessage.fields);
|
||||
@ -406,23 +395,28 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
public DynamicMessage build() {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
new DynamicMessage(type, fields,
|
||||
java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
|
||||
new DynamicMessage(
|
||||
type,
|
||||
fields,
|
||||
java.util.Arrays.copyOf(oneofCases, oneofCases.length),
|
||||
unknownFields));
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for DynamicMessage.parseFrom() methods to call. Throws
|
||||
* {@link InvalidProtocolBufferException} instead of
|
||||
* {@link UninitializedMessageException}.
|
||||
* Helper for DynamicMessage.parseFrom() methods to call. Throws {@link
|
||||
* InvalidProtocolBufferException} instead of {@link UninitializedMessageException}.
|
||||
*/
|
||||
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
new DynamicMessage(type, fields,
|
||||
java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields))
|
||||
.asInvalidProtocolBufferException();
|
||||
new DynamicMessage(
|
||||
type,
|
||||
fields,
|
||||
java.util.Arrays.copyOf(oneofCases, oneofCases.length),
|
||||
unknownFields))
|
||||
.asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
@ -431,8 +425,8 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
public DynamicMessage buildPartial() {
|
||||
fields.makeImmutable();
|
||||
DynamicMessage result =
|
||||
new DynamicMessage(type, fields,
|
||||
java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
|
||||
new DynamicMessage(
|
||||
type, fields, java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -441,7 +435,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
Builder result = new Builder(type);
|
||||
result.fields.mergeFrom(fields);
|
||||
result.mergeUnknownFields(unknownFields);
|
||||
System.arraycopy(oneofCases, 0, result.oneofCases, 0 , oneofCases.length);
|
||||
System.arraycopy(oneofCases, 0, result.oneofCases, 0, oneofCases.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -471,7 +465,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
|
||||
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"newBuilderForField is only valid for fields with message type.");
|
||||
"newBuilderForField is only valid for fields with message type.");
|
||||
}
|
||||
|
||||
return new Builder(field.getMessageType());
|
||||
@ -615,35 +609,30 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
@Override
|
||||
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
|
||||
this.unknownFields =
|
||||
UnknownFieldSet.newBuilder(this.unknownFields)
|
||||
.mergeFrom(unknownFields)
|
||||
.build();
|
||||
UnknownFieldSet.newBuilder(this.unknownFields).mergeFrom(unknownFields).build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Verifies that the field is a field of this message. */
|
||||
private void verifyContainingType(FieldDescriptor field) {
|
||||
if (field.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"FieldDescriptor does not match message type.");
|
||||
throw new IllegalArgumentException("FieldDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that the oneof is an oneof of this message. */
|
||||
private void verifyOneofContainingType(OneofDescriptor oneof) {
|
||||
if (oneof.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"OneofDescriptor does not match message type.");
|
||||
throw new IllegalArgumentException("OneofDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
|
||||
private void ensureSingularEnumValueDescriptor(
|
||||
FieldDescriptor field, Object value) {
|
||||
private void ensureSingularEnumValueDescriptor(FieldDescriptor field, Object value) {
|
||||
checkNotNull(value);
|
||||
if (!(value instanceof EnumValueDescriptor)) {
|
||||
throw new IllegalArgumentException(
|
||||
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
|
||||
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
|
||||
}
|
||||
// TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
|
||||
// set incorrect EnumValueDescriptors.
|
||||
@ -657,14 +646,13 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
}
|
||||
|
||||
/** Verifies the value for an enum field. */
|
||||
private void ensureEnumValueDescriptor(
|
||||
FieldDescriptor field, Object value) {
|
||||
private void ensureEnumValueDescriptor(FieldDescriptor field, Object value) {
|
||||
if (field.isRepeated()) {
|
||||
for (Object item : (List) value) {
|
||||
ensureSingularEnumValueDescriptor(field, item);
|
||||
}
|
||||
} else {
|
||||
ensureSingularEnumValueDescriptor(field, value);
|
||||
ensureSingularEnumValueDescriptor(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,14 +666,14 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
|
||||
// TODO(xiangl): need implementation for dynamic message
|
||||
throw new UnsupportedOperationException(
|
||||
"getFieldBuilder() called on a dynamic message type.");
|
||||
"getFieldBuilder() called on a dynamic message type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(FieldDescriptor field,
|
||||
int index) {
|
||||
public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(
|
||||
FieldDescriptor field, int index) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getRepeatedFieldBuilder() called on a dynamic message type.");
|
||||
"getRepeatedFieldBuilder() called on a dynamic message type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,26 +41,25 @@ import java.lang.annotation.Target;
|
||||
* backward-compatibility.
|
||||
*
|
||||
* <p>Usage guidelines:
|
||||
*
|
||||
* <ol>
|
||||
* <li>This annotation is used only on public API. Internal interfaces should not use it.</li>
|
||||
* <li>This annotation should only be added to new APIs. Adding it to an existing API is
|
||||
* considered API-breaking.</li>
|
||||
* <li>Removing this annotation from an API gives it stable status.</li>
|
||||
* <li>This annotation is used only on public API. Internal interfaces should not use it.
|
||||
* <li>This annotation should only be added to new APIs. Adding it to an existing API is
|
||||
* considered API-breaking.
|
||||
* <li>Removing this annotation from an API gives it stable status.
|
||||
* </ol>
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.PACKAGE,
|
||||
ElementType.TYPE})
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.PACKAGE,
|
||||
ElementType.TYPE
|
||||
})
|
||||
@Documented
|
||||
public @interface ExperimentalApi {
|
||||
/**
|
||||
* Context information such as links to discussion thread, tracking issue etc.
|
||||
*/
|
||||
/** Context information such as links to discussion thread, tracking issue etc. */
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
|
||||
|
||||
// All the methods below are extension implementation details.
|
||||
|
||||
/**
|
||||
* The API type that the extension is used for.
|
||||
*/
|
||||
/** The API type that the extension is used for. */
|
||||
protected enum ExtensionType {
|
||||
IMMUTABLE,
|
||||
MUTABLE,
|
||||
@ -60,24 +58,25 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
|
||||
|
||||
protected abstract ExtensionType getExtensionType();
|
||||
|
||||
/**
|
||||
* Type of a message extension.
|
||||
*/
|
||||
/** Type of a message extension. */
|
||||
public enum MessageType {
|
||||
PROTO1,
|
||||
PROTO2,
|
||||
}
|
||||
|
||||
/**
|
||||
* If the extension is a message extension (i.e., getLiteType() == MESSAGE),
|
||||
* returns the type of the message, otherwise undefined.
|
||||
* If the extension is a message extension (i.e., getLiteType() == MESSAGE), returns the type of
|
||||
* the message, otherwise undefined.
|
||||
*/
|
||||
public MessageType getMessageType() {
|
||||
return MessageType.PROTO2;
|
||||
}
|
||||
|
||||
protected abstract Object fromReflectionType(Object value);
|
||||
|
||||
protected abstract Object singularFromReflectionType(Object value);
|
||||
|
||||
protected abstract Object toReflectionType(Object value);
|
||||
|
||||
protected abstract Object singularToReflectionType(Object value);
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ 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.
|
||||
*
|
||||
* <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> {
|
||||
|
||||
@ -50,12 +50,9 @@ public abstract class ExtensionLite<ContainingType extends MessageLite, Type> {
|
||||
/** 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.
|
||||
*/
|
||||
/** 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;
|
||||
|
@ -40,11 +40,10 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A table of known extensions, searchable by name or field number. When
|
||||
* parsing a protocol message that might have extensions, you must provide
|
||||
* an {@code ExtensionRegistry} in which you have registered any extensions
|
||||
* that you want to be able to parse. Otherwise, those extensions will just
|
||||
* be treated like unknown fields.
|
||||
* A table of known extensions, searchable by name or field number. When parsing a protocol message
|
||||
* that might have extensions, you must provide an {@code ExtensionRegistry} in which you have
|
||||
* registered any extensions that you want to be able to parse. Otherwise, those extensions will
|
||||
* just be treated like unknown fields.
|
||||
*
|
||||
* <p>For example, if you had the {@code .proto} file:
|
||||
*
|
||||
@ -70,25 +69,22 @@ import java.util.Set;
|
||||
*
|
||||
* <p>Background:
|
||||
*
|
||||
* <p>You might wonder why this is necessary. Two alternatives might come to
|
||||
* mind. First, you might imagine a system where generated extensions are
|
||||
* automatically registered when their containing classes are loaded. This
|
||||
* is a popular technique, but is bad design; among other things, it creates a
|
||||
* situation where behavior can change depending on what classes happen to be
|
||||
* loaded. It also introduces a security vulnerability, because an
|
||||
* unprivileged class could cause its code to be called unexpectedly from a
|
||||
* privileged class by registering itself as an extension of the right type.
|
||||
* <p>You might wonder why this is necessary. Two alternatives might come to mind. First, you might
|
||||
* imagine a system where generated extensions are automatically registered when their containing
|
||||
* classes are loaded. This is a popular technique, but is bad design; among other things, it
|
||||
* creates a situation where behavior can change depending on what classes happen to be loaded. It
|
||||
* also introduces a security vulnerability, because an unprivileged class could cause its code to
|
||||
* be called unexpectedly from a privileged class by registering itself as an extension of the right
|
||||
* type.
|
||||
*
|
||||
* <p>Another option you might consider is lazy parsing: do not parse an
|
||||
* extension until it is first requested, at which point the caller must
|
||||
* provide a type to use. This introduces a different set of problems. First,
|
||||
* it would require a mutex lock any time an extension was accessed, which
|
||||
* would be slow. Second, corrupt data would not be detected until first
|
||||
* access, at which point it would be much harder to deal with it. Third, it
|
||||
* could violate the expectation that message objects are immutable, since the
|
||||
* type provided could be any arbitrary message class. An unprivileged user
|
||||
* could take advantage of this to inject a mutable object into a message
|
||||
* belonging to privileged code and create mischief.
|
||||
* <p>Another option you might consider is lazy parsing: do not parse an extension until it is first
|
||||
* requested, at which point the caller must provide a type to use. This introduces a different set
|
||||
* of problems. First, it would require a mutex lock any time an extension was accessed, which would
|
||||
* be slow. Second, corrupt data would not be detected until first access, at which point it would
|
||||
* be much harder to deal with it. Third, it could violate the expectation that message objects are
|
||||
* immutable, since the type provided could be any arbitrary message class. An unprivileged user
|
||||
* could take advantage of this to inject a mutable object into a message belonging to privileged
|
||||
* code and create mischief.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -116,8 +112,8 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
public final FieldDescriptor descriptor;
|
||||
|
||||
/**
|
||||
* A default instance of the extension's type, if it has a message type.
|
||||
* Otherwise, {@code null}.
|
||||
* A default instance of the extension's type, if it has a message type. Otherwise, {@code
|
||||
* null}.
|
||||
*/
|
||||
public final Message defaultInstance;
|
||||
|
||||
@ -125,48 +121,41 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
this.descriptor = descriptor;
|
||||
defaultInstance = null;
|
||||
}
|
||||
private ExtensionInfo(final FieldDescriptor descriptor,
|
||||
final Message defaultInstance) {
|
||||
|
||||
private ExtensionInfo(final FieldDescriptor descriptor, final Message defaultInstance) {
|
||||
this.descriptor = descriptor;
|
||||
this.defaultInstance = defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use {@link #findImmutableExtensionByName(String)} instead.
|
||||
*/
|
||||
/** Deprecated. Use {@link #findImmutableExtensionByName(String)} instead. */
|
||||
@Deprecated
|
||||
public ExtensionInfo findExtensionByName(final String fullName) {
|
||||
return findImmutableExtensionByName(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension for immutable APIs by fully-qualified field name,
|
||||
* in the proto namespace. i.e. {@code result.descriptor.fullName()} will
|
||||
* match {@code fullName} if a match is found.
|
||||
* Find an extension for immutable APIs by fully-qualified field name, in the proto namespace.
|
||||
* i.e. {@code result.descriptor.fullName()} will match {@code fullName} if a match is found.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
* @return Information about the extension if found, or {@code null} otherwise.
|
||||
*/
|
||||
public ExtensionInfo findImmutableExtensionByName(final String fullName) {
|
||||
return immutableExtensionsByName.get(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension for mutable APIs by fully-qualified field name,
|
||||
* in the proto namespace. i.e. {@code result.descriptor.fullName()} will
|
||||
* match {@code fullName} if a match is found.
|
||||
* Find an extension for mutable APIs by fully-qualified field name, in the proto namespace. i.e.
|
||||
* {@code result.descriptor.fullName()} will match {@code fullName} if a match is found.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
* @return Information about the extension if found, or {@code null} otherwise.
|
||||
*/
|
||||
public ExtensionInfo findMutableExtensionByName(final String fullName) {
|
||||
return mutableExtensionsByName.get(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use {@link #findImmutableExtensionByNumber(
|
||||
* Descriptors.Descriptor, int)}
|
||||
*/
|
||||
/** Deprecated. Use {@link #findImmutableExtensionByNumber( Descriptors.Descriptor, int)} */
|
||||
@Deprecated
|
||||
public ExtensionInfo findExtensionByNumber(
|
||||
final Descriptor containingType, final int fieldNumber) {
|
||||
return findImmutableExtensionByNumber(containingType, fieldNumber);
|
||||
@ -175,34 +164,28 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
/**
|
||||
* Find an extension by containing type and field number for immutable APIs.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
* @return Information about the extension if found, or {@code null} otherwise.
|
||||
*/
|
||||
public ExtensionInfo findImmutableExtensionByNumber(
|
||||
final Descriptor containingType, final int fieldNumber) {
|
||||
return immutableExtensionsByNumber.get(
|
||||
new DescriptorIntPair(containingType, fieldNumber));
|
||||
return immutableExtensionsByNumber.get(new DescriptorIntPair(containingType, fieldNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number for mutable APIs.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
* @return Information about the extension if found, or {@code null} otherwise.
|
||||
*/
|
||||
public ExtensionInfo findMutableExtensionByNumber(
|
||||
final Descriptor containingType, final int fieldNumber) {
|
||||
return mutableExtensionsByNumber.get(
|
||||
new DescriptorIntPair(containingType, fieldNumber));
|
||||
return mutableExtensionsByNumber.get(new DescriptorIntPair(containingType, fieldNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all extensions for mutable APIs by fully-qualified name of
|
||||
* extended class. Note that this method is more computationally expensive
|
||||
* than getting a single extension by name or number.
|
||||
* Find all extensions for mutable APIs by fully-qualified name of extended class. Note that this
|
||||
* method is more computationally expensive than getting a single extension by name or number.
|
||||
*
|
||||
* @return Information about the extensions found, or {@code null} if there
|
||||
* are none.
|
||||
* @return Information about the extensions found, or {@code null} if there are none.
|
||||
*/
|
||||
public Set<ExtensionInfo> getAllMutableExtensionsByExtendedType(final String fullName) {
|
||||
HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
|
||||
@ -215,12 +198,11 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all extensions for immutable APIs by fully-qualified name of
|
||||
* extended class. Note that this method is more computationally expensive
|
||||
* than getting a single extension by name or number.
|
||||
* Find all extensions for immutable APIs by fully-qualified name of extended class. Note that
|
||||
* this method is more computationally expensive than getting a single extension by name or
|
||||
* number.
|
||||
*
|
||||
* @return Information about the extensions found, or {@code null} if there
|
||||
* are none.
|
||||
* @return Information about the extensions found, or {@code null} if there are none.
|
||||
*/
|
||||
public Set<ExtensionInfo> getAllImmutableExtensionsByExtendedType(final String fullName) {
|
||||
HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
|
||||
@ -234,8 +216,8 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
|
||||
/** Add an extension from a generated file to the registry. */
|
||||
public void add(final Extension<?, ?> extension) {
|
||||
if (extension.getExtensionType() != Extension.ExtensionType.IMMUTABLE &&
|
||||
extension.getExtensionType() != Extension.ExtensionType.MUTABLE) {
|
||||
if (extension.getExtensionType() != Extension.ExtensionType.IMMUTABLE
|
||||
&& extension.getExtensionType() != Extension.ExtensionType.MUTABLE) {
|
||||
// do not support other extension types. ignore
|
||||
return;
|
||||
}
|
||||
@ -248,15 +230,14 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
}
|
||||
|
||||
static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
|
||||
if (extension.getDescriptor().getJavaType() ==
|
||||
FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (extension.getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (extension.getMessageDefaultInstance() == null) {
|
||||
throw new IllegalStateException(
|
||||
"Registered message-type extension had null default instance: " +
|
||||
extension.getDescriptor().getFullName());
|
||||
"Registered message-type extension had null default instance: "
|
||||
+ extension.getDescriptor().getFullName());
|
||||
}
|
||||
return new ExtensionInfo(extension.getDescriptor(),
|
||||
(Message) extension.getMessageDefaultInstance());
|
||||
return new ExtensionInfo(
|
||||
extension.getDescriptor(), (Message) extension.getMessageDefaultInstance());
|
||||
} else {
|
||||
return new ExtensionInfo(extension.getDescriptor(), null);
|
||||
}
|
||||
@ -266,8 +247,8 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
public void add(final FieldDescriptor type) {
|
||||
if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() must be provided a default instance when " +
|
||||
"adding an embedded message extension.");
|
||||
"ExtensionRegistry.add() must be provided a default instance when "
|
||||
+ "adding an embedded message extension.");
|
||||
}
|
||||
ExtensionInfo info = new ExtensionInfo(type, null);
|
||||
add(info, Extension.ExtensionType.IMMUTABLE);
|
||||
@ -278,11 +259,9 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
public void add(final FieldDescriptor type, final Message defaultInstance) {
|
||||
if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() provided a default instance for a " +
|
||||
"non-message extension.");
|
||||
"ExtensionRegistry.add() provided a default instance for a non-message extension.");
|
||||
}
|
||||
add(new ExtensionInfo(type, defaultInstance),
|
||||
Extension.ExtensionType.IMMUTABLE);
|
||||
add(new ExtensionInfo(type, defaultInstance), Extension.ExtensionType.IMMUTABLE);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
@ -291,22 +270,17 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
private ExtensionRegistry() {
|
||||
this.immutableExtensionsByName = new HashMap<String, ExtensionInfo>();
|
||||
this.mutableExtensionsByName = new HashMap<String, ExtensionInfo>();
|
||||
this.immutableExtensionsByNumber =
|
||||
new HashMap<DescriptorIntPair, ExtensionInfo>();
|
||||
this.mutableExtensionsByNumber =
|
||||
new HashMap<DescriptorIntPair, ExtensionInfo>();
|
||||
this.immutableExtensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
|
||||
this.mutableExtensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
|
||||
}
|
||||
|
||||
private ExtensionRegistry(ExtensionRegistry other) {
|
||||
super(other);
|
||||
this.immutableExtensionsByName =
|
||||
Collections.unmodifiableMap(other.immutableExtensionsByName);
|
||||
this.mutableExtensionsByName =
|
||||
Collections.unmodifiableMap(other.mutableExtensionsByName);
|
||||
this.immutableExtensionsByName = Collections.unmodifiableMap(other.immutableExtensionsByName);
|
||||
this.mutableExtensionsByName = Collections.unmodifiableMap(other.mutableExtensionsByName);
|
||||
this.immutableExtensionsByNumber =
|
||||
Collections.unmodifiableMap(other.immutableExtensionsByNumber);
|
||||
this.mutableExtensionsByNumber =
|
||||
Collections.unmodifiableMap(other.mutableExtensionsByNumber);
|
||||
this.mutableExtensionsByNumber = Collections.unmodifiableMap(other.mutableExtensionsByNumber);
|
||||
}
|
||||
|
||||
private final Map<String, ExtensionInfo> immutableExtensionsByName;
|
||||
@ -316,24 +290,19 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
|
||||
ExtensionRegistry(boolean empty) {
|
||||
super(EMPTY_REGISTRY_LITE);
|
||||
this.immutableExtensionsByName =
|
||||
Collections.<String, ExtensionInfo>emptyMap();
|
||||
this.mutableExtensionsByName =
|
||||
Collections.<String, ExtensionInfo>emptyMap();
|
||||
this.immutableExtensionsByNumber =
|
||||
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
|
||||
this.mutableExtensionsByNumber =
|
||||
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
|
||||
this.immutableExtensionsByName = Collections.<String, ExtensionInfo>emptyMap();
|
||||
this.mutableExtensionsByName = Collections.<String, ExtensionInfo>emptyMap();
|
||||
this.immutableExtensionsByNumber = Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
|
||||
this.mutableExtensionsByNumber = Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
|
||||
}
|
||||
|
||||
static final ExtensionRegistry EMPTY_REGISTRY = new ExtensionRegistry(true);
|
||||
|
||||
private void add(
|
||||
final ExtensionInfo extension,
|
||||
final Extension.ExtensionType extensionType) {
|
||||
private void add(final ExtensionInfo extension, final Extension.ExtensionType extensionType) {
|
||||
if (!extension.descriptor.isExtension()) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
|
||||
"(non-extension) field.");
|
||||
"ExtensionRegistry.add() was given a FieldDescriptor for a regular "
|
||||
+ "(non-extension) field.");
|
||||
}
|
||||
|
||||
Map<String, ExtensionInfo> extensionsByName;
|
||||
@ -354,15 +323,15 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
|
||||
extensionsByName.put(extension.descriptor.getFullName(), extension);
|
||||
extensionsByNumber.put(
|
||||
new DescriptorIntPair(extension.descriptor.getContainingType(),
|
||||
extension.descriptor.getNumber()),
|
||||
extension);
|
||||
new DescriptorIntPair(
|
||||
extension.descriptor.getContainingType(), extension.descriptor.getNumber()),
|
||||
extension);
|
||||
|
||||
final FieldDescriptor field = extension.descriptor;
|
||||
if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
|
||||
field.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
field.isOptional() &&
|
||||
field.getExtensionScope() == field.getMessageType()) {
|
||||
if (field.getContainingType().getOptions().getMessageSetWireFormat()
|
||||
&& field.getType() == FieldDescriptor.Type.MESSAGE
|
||||
&& field.isOptional()
|
||||
&& field.getExtensionScope() == field.getMessageType()) {
|
||||
// This is an extension of a MessageSet type defined within the extension
|
||||
// type's own scope. For backwards-compatibility, allow it to be looked
|
||||
// up by type name.
|
||||
@ -384,12 +353,13 @@ public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
public int hashCode() {
|
||||
return descriptor.hashCode() * ((1 << 16) - 1) + number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof DescriptorIntPair)) {
|
||||
return false;
|
||||
}
|
||||
final DescriptorIntPair other = (DescriptorIntPair)obj;
|
||||
final DescriptorIntPair other = (DescriptorIntPair) obj;
|
||||
return descriptor == other.descriptor && number == other.number;
|
||||
}
|
||||
}
|
||||
|
@ -35,16 +35,15 @@ import static com.google.protobuf.ExtensionRegistryLite.EMPTY_REGISTRY_LITE;
|
||||
/**
|
||||
* A factory object to create instances of {@link ExtensionRegistryLite}.
|
||||
*
|
||||
* <p>
|
||||
* This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries
|
||||
* are available, and if so, the instances returned are actually {@link ExtensionRegistry}.
|
||||
* <p>This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries are
|
||||
* available, and if so, the instances returned are actually {@link ExtensionRegistry}.
|
||||
*/
|
||||
final class ExtensionRegistryFactory {
|
||||
|
||||
static final String FULL_REGISTRY_CLASS_NAME = "com.google.protobuf.ExtensionRegistry";
|
||||
|
||||
/* Visible for Testing
|
||||
@Nullable */
|
||||
@Nullable */
|
||||
static final Class<?> EXTENSION_REGISTRY_CLASS = reflectExtensionRegistry();
|
||||
|
||||
/* @Nullable */
|
||||
@ -90,7 +89,7 @@ final class ExtensionRegistryFactory {
|
||||
|
||||
private static final ExtensionRegistryLite invokeSubclassFactory(String methodName)
|
||||
throws Exception {
|
||||
return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS
|
||||
.getDeclaredMethod(methodName).invoke(null);
|
||||
return (ExtensionRegistryLite)
|
||||
EXTENSION_REGISTRY_CLASS.getDeclaredMethod(methodName).invoke(null);
|
||||
}
|
||||
}
|
||||
|
@ -36,22 +36,20 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
|
||||
* <p>
|
||||
* If all of your types are lite types, then you only need to use
|
||||
* {@code ExtensionRegistryLite}. Similarly, if all your types are regular
|
||||
* types, then you only need {@link ExtensionRegistry}. Typically it does not
|
||||
* make sense to mix the two, since if you have any regular types in your
|
||||
* program, you then require the full runtime and lose all the benefits of
|
||||
* the lite runtime, so you might as well make all your types be regular types.
|
||||
* However, in some cases (e.g. when depending on multiple third-party libraries
|
||||
* where one uses lite types and one uses regular), you may find yourself
|
||||
* wanting to mix the two. In this case things get more complicated.
|
||||
* <p>
|
||||
* There are three factors to consider: Whether the type being extended is
|
||||
* lite, whether the embedded type (in the case of a message-typed extension)
|
||||
* is lite, and whether the extension itself is lite. Since all three are
|
||||
* declared in different files, they could all be different. Here are all
|
||||
* the combinations and which type of registry to use:
|
||||
*
|
||||
* <p>If all of your types are lite types, then you only need to use {@code ExtensionRegistryLite}.
|
||||
* Similarly, if all your types are regular types, then you only need {@link ExtensionRegistry}.
|
||||
* Typically it does not make sense to mix the two, since if you have any regular types in your
|
||||
* program, you then require the full runtime and lose all the benefits of the lite runtime, so you
|
||||
* might as well make all your types be regular types. However, in some cases (e.g. when depending
|
||||
* on multiple third-party libraries where one uses lite types and one uses regular), you may find
|
||||
* yourself wanting to mix the two. In this case things get more complicated.
|
||||
*
|
||||
* <p>There are three factors to consider: Whether the type being extended is lite, whether the
|
||||
* embedded type (in the case of a message-typed extension) is lite, and whether the extension
|
||||
* itself is lite. Since all three are declared in different files, they could all be different.
|
||||
* Here are all the combinations and which type of registry to use:
|
||||
*
|
||||
* <pre>
|
||||
* Extended type Inner type Extension Use registry
|
||||
* =======================================================================
|
||||
@ -60,13 +58,12 @@ import java.util.Map;
|
||||
* regular regular regular ExtensionRegistry
|
||||
* all other combinations not supported
|
||||
* </pre>
|
||||
* <p>
|
||||
* Note that just as regular types are not allowed to contain lite-type fields,
|
||||
* they are also not allowed to contain lite-type extensions. This is because
|
||||
* regular types must be fully accessible via reflection, which in turn means
|
||||
* that all the inner messages must also support reflection. On the other hand,
|
||||
* since regular types implement the entire lite interface, there is no problem
|
||||
* with embedding regular types inside lite types.
|
||||
*
|
||||
* <p>Note that just as regular types are not allowed to contain lite-type fields, they are also not
|
||||
* allowed to contain lite-type extensions. This is because regular types must be fully accessible
|
||||
* via reflection, which in turn means that all the inner messages must also support reflection. On
|
||||
* the other hand, since regular types implement the entire lite interface, there is no problem with
|
||||
* embedding regular types inside lite types.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -114,8 +111,8 @@ public class ExtensionRegistryLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or
|
||||
* {@code ExtensionRegistry} (if the full (non-Lite) proto libraries are available).
|
||||
* Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or {@code
|
||||
* ExtensionRegistry} (if the full (non-Lite) proto libraries are available).
|
||||
*/
|
||||
public static ExtensionRegistryLite getEmptyRegistry() {
|
||||
return ExtensionRegistryFactory.createEmpty();
|
||||
@ -130,32 +127,27 @@ public class ExtensionRegistryLite {
|
||||
/**
|
||||
* Find an extension by containing type and field number.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
* @return Information about the extension if found, or {@code null} otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <ContainingType extends MessageLite>
|
||||
GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
|
||||
findLiteExtensionByNumber(
|
||||
final ContainingType containingTypeDefaultInstance,
|
||||
final int fieldNumber) {
|
||||
GeneratedMessageLite.GeneratedExtension<ContainingType, ?> findLiteExtensionByNumber(
|
||||
final ContainingType containingTypeDefaultInstance, final int fieldNumber) {
|
||||
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
|
||||
extensionsByNumber.get(
|
||||
new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
|
||||
extensionsByNumber.get(new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
|
||||
}
|
||||
|
||||
/** Add an extension from a lite generated file to the registry. */
|
||||
public final void add(
|
||||
final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
|
||||
public final void add(final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
|
||||
extensionsByNumber.put(
|
||||
new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
|
||||
extension.getNumber()),
|
||||
extension);
|
||||
new ObjectIntPair(extension.getContainingTypeDefaultInstance(), extension.getNumber()),
|
||||
extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an extension from a lite generated file to the registry only if it is
|
||||
* a non-lite extension i.e. {@link GeneratedMessageLite.GeneratedExtension}. */
|
||||
* Add an extension from a lite generated file to the registry only if it is a non-lite extension
|
||||
* i.e. {@link GeneratedMessageLite.GeneratedExtension}.
|
||||
*/
|
||||
public final void add(ExtensionLite<?, ?> extension) {
|
||||
if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
|
||||
add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
|
||||
@ -178,23 +170,20 @@ public class ExtensionRegistryLite {
|
||||
|
||||
ExtensionRegistryLite() {
|
||||
this.extensionsByNumber =
|
||||
new HashMap<ObjectIntPair,
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?>>();
|
||||
new HashMap<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>();
|
||||
}
|
||||
static final ExtensionRegistryLite EMPTY_REGISTRY_LITE =
|
||||
new ExtensionRegistryLite(true);
|
||||
|
||||
static final ExtensionRegistryLite EMPTY_REGISTRY_LITE = new ExtensionRegistryLite(true);
|
||||
|
||||
ExtensionRegistryLite(ExtensionRegistryLite other) {
|
||||
if (other == EMPTY_REGISTRY_LITE) {
|
||||
this.extensionsByNumber = Collections.emptyMap();
|
||||
} else {
|
||||
this.extensionsByNumber =
|
||||
Collections.unmodifiableMap(other.extensionsByNumber);
|
||||
this.extensionsByNumber = Collections.unmodifiableMap(other.extensionsByNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ObjectIntPair,
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?>>
|
||||
private final Map<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>
|
||||
extensionsByNumber;
|
||||
|
||||
ExtensionRegistryLite(boolean empty) {
|
||||
@ -215,12 +204,13 @@ public class ExtensionRegistryLite {
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(object) * ((1 << 16) - 1) + number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof ObjectIntPair)) {
|
||||
return false;
|
||||
}
|
||||
final ObjectIntPair other = (ObjectIntPair)obj;
|
||||
final ObjectIntPair other = (ObjectIntPair) obj;
|
||||
return object == other.object && number == other.number;
|
||||
}
|
||||
}
|
||||
|
@ -41,32 +41,35 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class which represents an arbitrary set of fields of some message type.
|
||||
* This is used to implement {@link DynamicMessage}, and also to represent
|
||||
* extensions in {@link GeneratedMessage}. This class is package-private,
|
||||
* since outside users should probably be using {@link DynamicMessage}.
|
||||
* A class which represents an arbitrary set of fields of some message type. This is used to
|
||||
* implement {@link DynamicMessage}, and also to represent extensions in {@link GeneratedMessage}.
|
||||
* This class is package-private, since outside users should probably be using {@link
|
||||
* DynamicMessage}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
final class FieldSet<FieldDescriptorType extends
|
||||
FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
|
||||
final class FieldSet<
|
||||
FieldDescriptorType extends FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
|
||||
/**
|
||||
* Interface for a FieldDescriptor or lite extension descriptor. This
|
||||
* prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
|
||||
* Interface for a FieldDescriptor or lite extension descriptor. This prevents FieldSet from
|
||||
* depending on {@link Descriptors.FieldDescriptor}.
|
||||
*/
|
||||
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
|
||||
extends Comparable<T> {
|
||||
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>> extends Comparable<T> {
|
||||
int getNumber();
|
||||
|
||||
WireFormat.FieldType getLiteType();
|
||||
|
||||
WireFormat.JavaType getLiteJavaType();
|
||||
|
||||
boolean isRepeated();
|
||||
|
||||
boolean isPacked();
|
||||
|
||||
Internal.EnumLiteMap<?> getEnumType();
|
||||
|
||||
// If getLiteJavaType() == MESSAGE, this merges a message object of the
|
||||
// type into a builder of the type. Returns {@code to}.
|
||||
MessageLite.Builder internalMergeFrom(
|
||||
MessageLite.Builder to, MessageLite from);
|
||||
MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from);
|
||||
}
|
||||
|
||||
private final SmallSortedMap<FieldDescriptorType, Object> fields;
|
||||
@ -78,27 +81,23 @@ final class FieldSet<FieldDescriptorType extends
|
||||
this.fields = SmallSortedMap.newFieldMap(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty FieldSet. This is only used to initialize
|
||||
* DEFAULT_INSTANCE.
|
||||
*/
|
||||
/** Construct an empty FieldSet. This is only used to initialize DEFAULT_INSTANCE. */
|
||||
private FieldSet(final boolean dummy) {
|
||||
this.fields = SmallSortedMap.newFieldMap(0);
|
||||
makeImmutable();
|
||||
}
|
||||
|
||||
/** Construct a new FieldSet. */
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>>
|
||||
FieldSet<T> newFieldSet() {
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> newFieldSet() {
|
||||
return new FieldSet<T>();
|
||||
}
|
||||
|
||||
/** Get an immutable empty FieldSet. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>>
|
||||
FieldSet<T> emptySet() {
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> emptySet() {
|
||||
return DEFAULT_INSTANCE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
|
||||
|
||||
@ -118,8 +117,8 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the FieldSet is immutable. This is true if it is the
|
||||
* {@link #emptySet} or if {@link #makeImmutable} were called.
|
||||
* Returns whether the FieldSet is immutable. This is true if it is the {@link #emptySet} or if
|
||||
* {@link #makeImmutable} were called.
|
||||
*
|
||||
* @return whether the FieldSet is immutable.
|
||||
*/
|
||||
@ -147,8 +146,8 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the FieldSet. The returned FieldSet will be mutable even if the
|
||||
* original FieldSet was immutable.
|
||||
* Clones the FieldSet. The returned FieldSet will be mutable even if the original FieldSet was
|
||||
* immutable.
|
||||
*
|
||||
* @return the newly cloned FieldSet
|
||||
*/
|
||||
@ -162,8 +161,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
FieldDescriptorType descriptor = entry.getKey();
|
||||
clone.setField(descriptor, entry.getValue());
|
||||
}
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
FieldDescriptorType descriptor = entry.getKey();
|
||||
clone.setField(descriptor, entry.getValue());
|
||||
}
|
||||
@ -180,18 +178,14 @@ final class FieldSet<FieldDescriptorType extends
|
||||
hasLazyField = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a simple map containing all the fields.
|
||||
*/
|
||||
/** Get a simple map containing all the fields. */
|
||||
public Map<FieldDescriptorType, Object> getAllFields() {
|
||||
if (hasLazyField) {
|
||||
SmallSortedMap<FieldDescriptorType, Object> result =
|
||||
SmallSortedMap.newFieldMap(16);
|
||||
SmallSortedMap<FieldDescriptorType, Object> result = SmallSortedMap.newFieldMap(16);
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
cloneFieldEntry(result, fields.getArrayEntryAt(i));
|
||||
}
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
cloneFieldEntry(result, entry);
|
||||
}
|
||||
if (fields.isImmutable()) {
|
||||
@ -202,8 +196,8 @@ final class FieldSet<FieldDescriptorType extends
|
||||
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
|
||||
}
|
||||
|
||||
private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
|
||||
Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
private void cloneFieldEntry(
|
||||
Map<FieldDescriptorType, Object> map, Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
FieldDescriptorType key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof LazyField) {
|
||||
@ -214,37 +208,30 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator to the field map. This iterator should not be leaked out
|
||||
* of the protobuf library as it is not protected from mutation when fields
|
||||
* is not immutable.
|
||||
* Get an iterator to the field map. This iterator should not be leaked out of the protobuf
|
||||
* library as it is not protected from mutation when fields is not immutable.
|
||||
*/
|
||||
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
|
||||
if (hasLazyField) {
|
||||
return new LazyIterator<FieldDescriptorType>(
|
||||
fields.entrySet().iterator());
|
||||
return new LazyIterator<FieldDescriptorType>(fields.entrySet().iterator());
|
||||
}
|
||||
return fields.entrySet().iterator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#hasField(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
/** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */
|
||||
public boolean hasField(final FieldDescriptorType descriptor) {
|
||||
if (descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"hasField() can only be called on non-repeated fields.");
|
||||
throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
|
||||
}
|
||||
|
||||
return fields.get(descriptor) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)}. This method
|
||||
* returns {@code null} if the field is not set; in this case it is up
|
||||
* to the caller to fetch the field's default value.
|
||||
* Useful for implementing {@link Message#getField(Descriptors.FieldDescriptor)}. This method
|
||||
* returns {@code null} if the field is not set; in this case it is up to the caller to fetch the
|
||||
* field's default value.
|
||||
*/
|
||||
public Object getField(final FieldDescriptorType descriptor) {
|
||||
Object o = fields.get(descriptor);
|
||||
@ -255,16 +242,14 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
|
||||
* Useful for implementing {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void setField(final FieldDescriptorType descriptor,
|
||||
Object value) {
|
||||
public void setField(final FieldDescriptorType descriptor, Object value) {
|
||||
if (descriptor.isRepeated()) {
|
||||
if (!(value instanceof List)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
}
|
||||
|
||||
// Wrap the contents in a new list so that the caller cannot change
|
||||
@ -285,10 +270,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
fields.put(descriptor, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
/** Useful for implementing {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
|
||||
public void clearField(final FieldDescriptorType descriptor) {
|
||||
fields.remove(descriptor);
|
||||
if (fields.isEmpty()) {
|
||||
@ -296,14 +278,11 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
/** Useful for implementing {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
|
||||
public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object value = getField(descriptor);
|
||||
@ -314,15 +293,11 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
|
||||
*/
|
||||
public Object getRepeatedField(final FieldDescriptorType descriptor,
|
||||
final int index) {
|
||||
/** Useful for implementing {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
|
||||
public Object getRepeatedField(final FieldDescriptorType descriptor, final int index) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object value = getField(descriptor);
|
||||
@ -335,16 +310,15 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
|
||||
* Useful for implementing {@link
|
||||
* Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setRepeatedField(final FieldDescriptorType descriptor,
|
||||
final int index,
|
||||
final Object value) {
|
||||
public void setRepeatedField(
|
||||
final FieldDescriptorType descriptor, final int index, final Object value) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object list = getField(descriptor);
|
||||
@ -357,15 +331,14 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
|
||||
* Useful for implementing {@link
|
||||
* Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addRepeatedField(final FieldDescriptorType descriptor,
|
||||
final Object value) {
|
||||
public void addRepeatedField(final FieldDescriptorType descriptor, final Object value) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"addRepeatedField() can only be called on repeated fields.");
|
||||
"addRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
verifyType(descriptor.getLiteType(), value);
|
||||
@ -383,36 +356,45 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the given object is of the correct type to be a valid
|
||||
* value for the given field. (For repeated fields, this checks if the
|
||||
* object is the right type to be one element of the field.)
|
||||
* Verifies that the given object is of the correct type to be a valid value for the given field.
|
||||
* (For repeated fields, this checks if the object is the right type to be one element of the
|
||||
* field.)
|
||||
*
|
||||
* @throws IllegalArgumentException The value is not of the right type.
|
||||
*/
|
||||
private static void verifyType(final WireFormat.FieldType type,
|
||||
final Object value) {
|
||||
private static void verifyType(final WireFormat.FieldType type, final Object value) {
|
||||
checkNotNull(value);
|
||||
|
||||
boolean isValid = false;
|
||||
switch (type.getJavaType()) {
|
||||
case INT: isValid = value instanceof Integer ; break;
|
||||
case LONG: isValid = value instanceof Long ; break;
|
||||
case FLOAT: isValid = value instanceof Float ; break;
|
||||
case DOUBLE: isValid = value instanceof Double ; break;
|
||||
case BOOLEAN: isValid = value instanceof Boolean ; break;
|
||||
case STRING: isValid = value instanceof String ; break;
|
||||
case INT:
|
||||
isValid = value instanceof Integer;
|
||||
break;
|
||||
case LONG:
|
||||
isValid = value instanceof Long;
|
||||
break;
|
||||
case FLOAT:
|
||||
isValid = value instanceof Float;
|
||||
break;
|
||||
case DOUBLE:
|
||||
isValid = value instanceof Double;
|
||||
break;
|
||||
case BOOLEAN:
|
||||
isValid = value instanceof Boolean;
|
||||
break;
|
||||
case STRING:
|
||||
isValid = value instanceof String;
|
||||
break;
|
||||
case BYTE_STRING:
|
||||
isValid = value instanceof ByteString || value instanceof byte[];
|
||||
break;
|
||||
case ENUM:
|
||||
// TODO(kenton): Caller must do type checking here, I guess.
|
||||
isValid =
|
||||
(value instanceof Integer || value instanceof Internal.EnumLite);
|
||||
isValid = (value instanceof Integer || value instanceof Internal.EnumLite);
|
||||
break;
|
||||
case MESSAGE:
|
||||
// TODO(kenton): Caller must do type checking here, I guess.
|
||||
isValid =
|
||||
(value instanceof MessageLite) || (value instanceof LazyField);
|
||||
isValid = (value instanceof MessageLite) || (value instanceof LazyField);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -425,7 +407,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
// isn't a big deal, though, since it would only really apply when using
|
||||
// reflection and generally people don't chain reflection setters.
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,10 +415,9 @@ final class FieldSet<FieldDescriptorType extends
|
||||
// Parsing and serialization
|
||||
|
||||
/**
|
||||
* See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
|
||||
* itself does not have any way of knowing about required fields that
|
||||
* aren't actually present in the set, it is up to the caller to check
|
||||
* that all required fields are present.
|
||||
* See {@link Message#isInitialized()}. Note: Since {@code FieldSet} itself does not have any way
|
||||
* of knowing about required fields that aren't actually present in the set, it is up to the
|
||||
* caller to check that all required fields are present.
|
||||
*/
|
||||
public boolean isInitialized() {
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
@ -444,8 +425,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
if (!isInitialized(entry)) {
|
||||
return false;
|
||||
}
|
||||
@ -454,13 +434,11 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isInitialized(
|
||||
final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
private boolean isInitialized(final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
|
||||
if (descriptor.isRepeated()) {
|
||||
for (final MessageLite element:
|
||||
(List<MessageLite>) entry.getValue()) {
|
||||
for (final MessageLite element : (List<MessageLite>) entry.getValue()) {
|
||||
if (!element.isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
@ -485,11 +463,9 @@ final class FieldSet<FieldDescriptorType extends
|
||||
/**
|
||||
* Given a field type, return the wire type.
|
||||
*
|
||||
* @returns One of the {@code WIRETYPE_} constants defined in
|
||||
* {@link WireFormat}.
|
||||
* @return One of the {@code WIRETYPE_} constants defined in {@link WireFormat}.
|
||||
*/
|
||||
static int getWireFormatForFieldType(final WireFormat.FieldType type,
|
||||
boolean isPacked) {
|
||||
static int getWireFormatForFieldType(final WireFormat.FieldType type, boolean isPacked) {
|
||||
if (isPacked) {
|
||||
return WireFormat.WIRETYPE_LENGTH_DELIMITED;
|
||||
} else {
|
||||
@ -497,16 +473,12 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
|
||||
* {@link FieldSet}.
|
||||
*/
|
||||
/** Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}. */
|
||||
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
|
||||
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
|
||||
mergeFromField(other.fields.getArrayEntryAt(i));
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
other.fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : other.fields.getOverflowEntries()) {
|
||||
mergeFromField(entry);
|
||||
}
|
||||
}
|
||||
@ -523,8 +495,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void mergeFromField(
|
||||
final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
private void mergeFromField(final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
Object otherValue = entry.getValue();
|
||||
if (otherValue instanceof LazyField) {
|
||||
@ -546,9 +517,10 @@ final class FieldSet<FieldDescriptorType extends
|
||||
fields.put(descriptor, cloneIfMutable(otherValue));
|
||||
} else {
|
||||
// Merge the messages.
|
||||
value = descriptor.internalMergeFrom(
|
||||
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
|
||||
.build();
|
||||
value =
|
||||
descriptor
|
||||
.internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
|
||||
.build();
|
||||
|
||||
fields.put(descriptor, value);
|
||||
}
|
||||
@ -561,72 +533,59 @@ final class FieldSet<FieldDescriptorType extends
|
||||
// other class. Probably WireFormat.
|
||||
|
||||
/**
|
||||
* Read a field of any primitive type for immutable messages from a
|
||||
* CodedInputStream. Enums, groups, and embedded messages are not handled by
|
||||
* this method.
|
||||
* Read a field of any primitive type for immutable messages from a CodedInputStream. Enums,
|
||||
* groups, and embedded messages are not handled by this method.
|
||||
*
|
||||
* @param input The stream from which to read.
|
||||
* @param type Declared type of the field.
|
||||
* @param checkUtf8 When true, check that the input is valid utf8.
|
||||
* @return An object representing the field's value, of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @return An object representing the field's value, of the exact type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
public static Object readPrimitiveField(
|
||||
CodedInputStream input,
|
||||
final WireFormat.FieldType type,
|
||||
boolean checkUtf8) throws IOException {
|
||||
CodedInputStream input, final WireFormat.FieldType type, boolean checkUtf8)
|
||||
throws IOException {
|
||||
if (checkUtf8) {
|
||||
return WireFormat.readPrimitiveField(input, type,
|
||||
WireFormat.Utf8Validation.STRICT);
|
||||
return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.STRICT);
|
||||
} else {
|
||||
return WireFormat.readPrimitiveField(input, type,
|
||||
WireFormat.Utf8Validation.LOOSE);
|
||||
return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.LOOSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** See {@link Message#writeTo(CodedOutputStream)}. */
|
||||
public void writeTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
public void writeTo(final CodedOutputStream output) throws IOException {
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
final Map.Entry<FieldDescriptorType, Object> entry =
|
||||
fields.getArrayEntryAt(i);
|
||||
final Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
|
||||
writeField(entry.getKey(), entry.getValue(), output);
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
writeField(entry.getKey(), entry.getValue(), output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #writeTo} but uses MessageSet wire format.
|
||||
*/
|
||||
public void writeMessageSetTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
/** Like {@link #writeTo} but uses MessageSet wire format. */
|
||||
public void writeMessageSetTo(final CodedOutputStream output) throws IOException {
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
writeMessageSetTo(fields.getArrayEntryAt(i), output);
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
writeMessageSetTo(entry, output);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMessageSetTo(
|
||||
final Map.Entry<FieldDescriptorType, Object> entry,
|
||||
final CodedOutputStream output) throws IOException {
|
||||
final Map.Entry<FieldDescriptorType, Object> entry, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
|
||||
!descriptor.isRepeated() && !descriptor.isPacked()) {
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
|
||||
&& !descriptor.isRepeated()
|
||||
&& !descriptor.isPacked()) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof LazyField) {
|
||||
value = ((LazyField) value).getValue();
|
||||
}
|
||||
output.writeMessageSetExtension(entry.getKey().getNumber(),
|
||||
(MessageLite) value);
|
||||
output.writeMessageSetExtension(entry.getKey().getNumber(), (MessageLite) value);
|
||||
} else {
|
||||
writeField(descriptor, entry.getValue(), output);
|
||||
}
|
||||
@ -636,18 +595,17 @@ final class FieldSet<FieldDescriptorType extends
|
||||
* Write a single tag-value pair to the stream.
|
||||
*
|
||||
* @param output The output stream.
|
||||
* @param type The field's type.
|
||||
* @param type The field's type.
|
||||
* @param number The field's number.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @param value Object representing the field's value. Must be of the exact type which would be
|
||||
* returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
static void writeElement(
|
||||
final CodedOutputStream output,
|
||||
final WireFormat.FieldType type,
|
||||
final int number,
|
||||
final Object value) throws IOException {
|
||||
final Object value)
|
||||
throws IOException {
|
||||
// Special case for groups, which need a start and end tag; other fields
|
||||
// can just use writeTag() and writeFieldNoTag().
|
||||
if (type == WireFormat.FieldType.GROUP) {
|
||||
@ -663,26 +621,43 @@ final class FieldSet<FieldDescriptorType extends
|
||||
*
|
||||
* @param output The output stream.
|
||||
* @param type The field's type.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @param value Object representing the field's value. Must be of the exact type which would be
|
||||
* returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
static void writeElementNoTag(
|
||||
final CodedOutputStream output,
|
||||
final WireFormat.FieldType type,
|
||||
final Object value) throws IOException {
|
||||
final CodedOutputStream output, final WireFormat.FieldType type, final Object value)
|
||||
throws IOException {
|
||||
switch (type) {
|
||||
case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
|
||||
case FLOAT : output.writeFloatNoTag ((Float ) value); break;
|
||||
case INT64 : output.writeInt64NoTag ((Long ) value); break;
|
||||
case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
|
||||
case INT32 : output.writeInt32NoTag ((Integer ) value); break;
|
||||
case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
|
||||
case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
|
||||
case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
|
||||
case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
|
||||
case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
|
||||
case DOUBLE:
|
||||
output.writeDoubleNoTag((Double) value);
|
||||
break;
|
||||
case FLOAT:
|
||||
output.writeFloatNoTag((Float) value);
|
||||
break;
|
||||
case INT64:
|
||||
output.writeInt64NoTag((Long) value);
|
||||
break;
|
||||
case UINT64:
|
||||
output.writeUInt64NoTag((Long) value);
|
||||
break;
|
||||
case INT32:
|
||||
output.writeInt32NoTag((Integer) value);
|
||||
break;
|
||||
case FIXED64:
|
||||
output.writeFixed64NoTag((Long) value);
|
||||
break;
|
||||
case FIXED32:
|
||||
output.writeFixed32NoTag((Integer) value);
|
||||
break;
|
||||
case BOOL:
|
||||
output.writeBoolNoTag((Boolean) value);
|
||||
break;
|
||||
case GROUP:
|
||||
output.writeGroupNoTag((MessageLite) value);
|
||||
break;
|
||||
case MESSAGE:
|
||||
output.writeMessageNoTag((MessageLite) value);
|
||||
break;
|
||||
case STRING:
|
||||
if (value instanceof ByteString) {
|
||||
output.writeBytesNoTag((ByteString) value);
|
||||
@ -697,11 +672,21 @@ final class FieldSet<FieldDescriptorType extends
|
||||
output.writeByteArrayNoTag((byte[]) value);
|
||||
}
|
||||
break;
|
||||
case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
|
||||
case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
|
||||
case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
|
||||
case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
|
||||
case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
|
||||
case UINT32:
|
||||
output.writeUInt32NoTag((Integer) value);
|
||||
break;
|
||||
case SFIXED32:
|
||||
output.writeSFixed32NoTag((Integer) value);
|
||||
break;
|
||||
case SFIXED64:
|
||||
output.writeSFixed64NoTag((Long) value);
|
||||
break;
|
||||
case SINT32:
|
||||
output.writeSInt32NoTag((Integer) value);
|
||||
break;
|
||||
case SINT64:
|
||||
output.writeSInt64NoTag((Long) value);
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
if (value instanceof Internal.EnumLite) {
|
||||
@ -714,14 +699,13 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/** Write a single field. */
|
||||
public static void writeField(final FieldDescriptorLite<?> descriptor,
|
||||
final Object value,
|
||||
final CodedOutputStream output)
|
||||
throws IOException {
|
||||
public static void writeField(
|
||||
final FieldDescriptorLite<?> descriptor, final Object value, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
WireFormat.FieldType type = descriptor.getLiteType();
|
||||
int number = descriptor.getNumber();
|
||||
if (descriptor.isRepeated()) {
|
||||
final List<?> valueList = (List<?>)value;
|
||||
final List<?> valueList = (List<?>) value;
|
||||
if (descriptor.isPacked()) {
|
||||
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
// Compute the total data size so the length can be written.
|
||||
@ -749,44 +733,39 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Message#getSerializedSize()}. It's up to the caller to cache
|
||||
* the resulting size if desired.
|
||||
* See {@link Message#getSerializedSize()}. It's up to the caller to cache the resulting size if
|
||||
* desired.
|
||||
*/
|
||||
public int getSerializedSize() {
|
||||
int size = 0;
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
final Map.Entry<FieldDescriptorType, Object> entry =
|
||||
fields.getArrayEntryAt(i);
|
||||
final Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
|
||||
size += computeFieldSize(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
size += computeFieldSize(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #getSerializedSize} but uses MessageSet wire format.
|
||||
*/
|
||||
/** Like {@link #getSerializedSize} but uses MessageSet wire format. */
|
||||
public int getMessageSetSerializedSize() {
|
||||
int size = 0;
|
||||
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
|
||||
size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
|
||||
}
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry :
|
||||
fields.getOverflowEntries()) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
|
||||
size += getMessageSetSerializedSize(entry);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private int getMessageSetSerializedSize(
|
||||
final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
private int getMessageSetSerializedSize(final Map.Entry<FieldDescriptorType, Object> entry) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
|
||||
&& !descriptor.isRepeated() && !descriptor.isPacked()) {
|
||||
&& !descriptor.isRepeated()
|
||||
&& !descriptor.isPacked()) {
|
||||
if (value instanceof LazyField) {
|
||||
return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
|
||||
entry.getKey().getNumber(), (LazyField) value);
|
||||
@ -800,15 +779,13 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* single tag/value pair of arbitrary type.
|
||||
* Compute the number of bytes that would be needed to encode a single tag/value pair of arbitrary
|
||||
* type.
|
||||
*
|
||||
* @param type The field's type.
|
||||
* @param type The field's type.
|
||||
* @param number The field's number.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @param value Object representing the field's value. Must be of the exact type which would be
|
||||
* returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
static int computeElementSize(
|
||||
final WireFormat.FieldType type, final int number, final Object value) {
|
||||
@ -822,46 +799,57 @@ final class FieldSet<FieldDescriptorType extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* particular value of arbitrary type, excluding tag.
|
||||
* Compute the number of bytes that would be needed to encode a particular value of arbitrary
|
||||
* type, excluding tag.
|
||||
*
|
||||
* @param type The field's type.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @param type The field's type.
|
||||
* @param value Object representing the field's value. Must be of the exact type which would be
|
||||
* returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
static int computeElementSizeNoTag(
|
||||
final WireFormat.FieldType type, final Object value) {
|
||||
static int computeElementSizeNoTag(final WireFormat.FieldType type, final Object value) {
|
||||
switch (type) {
|
||||
// Note: Minor violation of 80-char limit rule here because this would
|
||||
// actually be harder to read if we wrapped the lines.
|
||||
case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
|
||||
case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
|
||||
case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
|
||||
case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
|
||||
case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
|
||||
case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
|
||||
case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
|
||||
case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
|
||||
case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
|
||||
case BYTES :
|
||||
// Note: Minor violation of 80-char limit rule here because this would
|
||||
// actually be harder to read if we wrapped the lines.
|
||||
case DOUBLE:
|
||||
return CodedOutputStream.computeDoubleSizeNoTag((Double) value);
|
||||
case FLOAT:
|
||||
return CodedOutputStream.computeFloatSizeNoTag((Float) value);
|
||||
case INT64:
|
||||
return CodedOutputStream.computeInt64SizeNoTag((Long) value);
|
||||
case UINT64:
|
||||
return CodedOutputStream.computeUInt64SizeNoTag((Long) value);
|
||||
case INT32:
|
||||
return CodedOutputStream.computeInt32SizeNoTag((Integer) value);
|
||||
case FIXED64:
|
||||
return CodedOutputStream.computeFixed64SizeNoTag((Long) value);
|
||||
case FIXED32:
|
||||
return CodedOutputStream.computeFixed32SizeNoTag((Integer) value);
|
||||
case BOOL:
|
||||
return CodedOutputStream.computeBoolSizeNoTag((Boolean) value);
|
||||
case GROUP:
|
||||
return CodedOutputStream.computeGroupSizeNoTag((MessageLite) value);
|
||||
case BYTES:
|
||||
if (value instanceof ByteString) {
|
||||
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
|
||||
} else {
|
||||
return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
|
||||
}
|
||||
case STRING :
|
||||
case STRING:
|
||||
if (value instanceof ByteString) {
|
||||
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
|
||||
} else {
|
||||
return CodedOutputStream.computeStringSizeNoTag((String) value);
|
||||
}
|
||||
case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
|
||||
case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
|
||||
case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
|
||||
case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
|
||||
case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
|
||||
case UINT32:
|
||||
return CodedOutputStream.computeUInt32SizeNoTag((Integer) value);
|
||||
case SFIXED32:
|
||||
return CodedOutputStream.computeSFixed32SizeNoTag((Integer) value);
|
||||
case SFIXED64:
|
||||
return CodedOutputStream.computeSFixed64SizeNoTag((Long) value);
|
||||
case SINT32:
|
||||
return CodedOutputStream.computeSInt32SizeNoTag((Integer) value);
|
||||
case SINT64:
|
||||
return CodedOutputStream.computeSInt64SizeNoTag((Long) value);
|
||||
|
||||
case MESSAGE:
|
||||
if (value instanceof LazyField) {
|
||||
@ -872,36 +860,31 @@ final class FieldSet<FieldDescriptorType extends
|
||||
|
||||
case ENUM:
|
||||
if (value instanceof Internal.EnumLite) {
|
||||
return CodedOutputStream.computeEnumSizeNoTag(
|
||||
((Internal.EnumLite) value).getNumber());
|
||||
return CodedOutputStream.computeEnumSizeNoTag(((Internal.EnumLite) value).getNumber());
|
||||
} else {
|
||||
return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
"There is no way to get here, but the compiler thinks otherwise.");
|
||||
throw new RuntimeException("There is no way to get here, but the compiler thinks otherwise.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes needed to encode a particular field.
|
||||
*/
|
||||
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
|
||||
final Object value) {
|
||||
/** Compute the number of bytes needed to encode a particular field. */
|
||||
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor, final Object value) {
|
||||
WireFormat.FieldType type = descriptor.getLiteType();
|
||||
int number = descriptor.getNumber();
|
||||
if (descriptor.isRepeated()) {
|
||||
if (descriptor.isPacked()) {
|
||||
int dataSize = 0;
|
||||
for (final Object element : (List<?>)value) {
|
||||
for (final Object element : (List<?>) value) {
|
||||
dataSize += computeElementSizeNoTag(type, element);
|
||||
}
|
||||
return dataSize +
|
||||
CodedOutputStream.computeTagSize(number) +
|
||||
CodedOutputStream.computeRawVarint32Size(dataSize);
|
||||
return dataSize
|
||||
+ CodedOutputStream.computeTagSize(number)
|
||||
+ CodedOutputStream.computeRawVarint32Size(dataSize);
|
||||
} else {
|
||||
int size = 0;
|
||||
for (final Object element : (List<?>)value) {
|
||||
for (final Object element : (List<?>) value) {
|
||||
size += computeElementSize(type, number, element);
|
||||
}
|
||||
return size;
|
||||
|
@ -42,11 +42,11 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class FloatArrayList
|
||||
extends AbstractProtobufList<Float>
|
||||
final class FloatArrayList extends AbstractProtobufList<Float>
|
||||
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -55,9 +55,7 @@ final class FloatArrayList
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing store for the list.
|
||||
*/
|
||||
/** The backing store for the list. */
|
||||
private float[] array;
|
||||
|
||||
/**
|
||||
@ -66,16 +64,13 @@ final class FloatArrayList
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code FloatArrayList} with default capacity.
|
||||
*/
|
||||
/** Constructs a new mutable {@code FloatArrayList} with default capacity. */
|
||||
FloatArrayList() {
|
||||
this(new float[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code FloatArrayList}
|
||||
* containing the same elements as {@code other}.
|
||||
* Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
|
||||
*/
|
||||
private FloatArrayList(float[] other, int size) {
|
||||
array = other;
|
||||
@ -169,17 +164,13 @@ final class FloatArrayList
|
||||
addFloat(index, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(Float)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Float)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addFloat(float element) {
|
||||
addFloat(size, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(int, Float)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(int, Float)} but more efficient in that it doesn't box the element. */
|
||||
private void addFloat(int index, float element) {
|
||||
ensureIsMutable();
|
||||
if (index < 0 || index > size) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,11 +42,11 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class IntArrayList
|
||||
extends AbstractProtobufList<Integer>
|
||||
final class IntArrayList extends AbstractProtobufList<Integer>
|
||||
implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final IntArrayList EMPTY_LIST = new IntArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -55,9 +55,7 @@ final class IntArrayList
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing store for the list.
|
||||
*/
|
||||
/** The backing store for the list. */
|
||||
private int[] array;
|
||||
|
||||
/**
|
||||
@ -66,16 +64,13 @@ final class IntArrayList
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code IntArrayList} with default capacity.
|
||||
*/
|
||||
/** Constructs a new mutable {@code IntArrayList} with default capacity. */
|
||||
IntArrayList() {
|
||||
this(new int[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code IntArrayList}
|
||||
* containing the same elements as {@code other}.
|
||||
* Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
|
||||
*/
|
||||
private IntArrayList(int[] other, int size) {
|
||||
array = other;
|
||||
@ -169,17 +164,13 @@ final class IntArrayList
|
||||
addInt(index, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Integer)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addInt(int element) {
|
||||
addInt(size, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element. */
|
||||
private void addInt(int index, int element) {
|
||||
ensureIsMutable();
|
||||
if (index < 0 || index > size) {
|
||||
|
@ -45,10 +45,9 @@ import java.util.RandomAccess;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The classes contained within are used internally by the Protocol Buffer
|
||||
* library and generated message implementations. They are public only because
|
||||
* those generated messages do not reside in the {@code protobuf} package.
|
||||
* Others should not use this class directly.
|
||||
* The classes contained within are used internally by the Protocol Buffer library and generated
|
||||
* message implementations. They are public only because those generated messages do not reside in
|
||||
* the {@code protobuf} package. Others should not use this class directly.
|
||||
*
|
||||
* @author kenton@google.com (Kenton Varda)
|
||||
*/
|
||||
@ -59,9 +58,7 @@ public final class Internal {
|
||||
static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||
|
||||
/**
|
||||
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
|
||||
*/
|
||||
/** Throws an appropriate {@link NullPointerException} if the given objects is {@code null}. */
|
||||
static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
@ -69,9 +66,7 @@ public final class Internal {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
|
||||
*/
|
||||
/** Throws an appropriate {@link NullPointerException} if the given objects is {@code null}. */
|
||||
static <T> T checkNotNull(T obj, String message) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(message);
|
||||
@ -80,73 +75,63 @@ public final class Internal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by generated code to construct default values for string
|
||||
* fields.
|
||||
* <p>
|
||||
* The protocol compiler does not actually contain a UTF-8 decoder -- it
|
||||
* just pushes UTF-8-encoded text around without touching it. The one place
|
||||
* where this presents a problem is when generating Java string literals.
|
||||
* Unicode characters in the string literal would normally need to be encoded
|
||||
* using a Unicode escape sequence, which would require decoding them.
|
||||
* To get around this, protoc instead embeds the UTF-8 bytes into the
|
||||
* generated code and leaves it to the runtime library to decode them.
|
||||
* <p>
|
||||
* It gets worse, though. If protoc just generated a byte array, like:
|
||||
* new byte[] {0x12, 0x34, 0x56, 0x78}
|
||||
* Java actually generates *code* which allocates an array and then fills
|
||||
* in each value. This is much less efficient than just embedding the bytes
|
||||
* directly into the bytecode. To get around this, we need another
|
||||
* work-around. String literals are embedded directly, so protoc actually
|
||||
* generates a string literal corresponding to the bytes. The easiest way
|
||||
* to do this is to use the ISO-8859-1 character set, which corresponds to
|
||||
* the first 256 characters of the Unicode range. Protoc can then use
|
||||
* good old CEscape to generate the string.
|
||||
* <p>
|
||||
* So we have a string literal which represents a set of bytes which
|
||||
* represents another string. This function -- stringDefaultValue --
|
||||
* converts from the generated string to the string we actually want. The
|
||||
* generated code calls this automatically.
|
||||
* Helper called by generated code to construct default values for string fields.
|
||||
*
|
||||
* <p>The protocol compiler does not actually contain a UTF-8 decoder -- it just pushes
|
||||
* UTF-8-encoded text around without touching it. The one place where this presents a problem is
|
||||
* when generating Java string literals. Unicode characters in the string literal would normally
|
||||
* need to be encoded using a Unicode escape sequence, which would require decoding them. To get
|
||||
* around this, protoc instead embeds the UTF-8 bytes into the generated code and leaves it to the
|
||||
* runtime library to decode them.
|
||||
*
|
||||
* <p>It gets worse, though. If protoc just generated a byte array, like: new byte[] {0x12, 0x34,
|
||||
* 0x56, 0x78} Java actually generates *code* which allocates an array and then fills in each
|
||||
* value. This is much less efficient than just embedding the bytes directly into the bytecode. To
|
||||
* get around this, we need another work-around. String literals are embedded directly, so protoc
|
||||
* actually generates a string literal corresponding to the bytes. The easiest way to do this is
|
||||
* to use the ISO-8859-1 character set, which corresponds to the first 256 characters of the
|
||||
* Unicode range. Protoc can then use good old CEscape to generate the string.
|
||||
*
|
||||
* <p>So we have a string literal which represents a set of bytes which represents another string.
|
||||
* This function -- stringDefaultValue -- converts from the generated string to the string we
|
||||
* actually want. The generated code calls this automatically.
|
||||
*/
|
||||
public static String stringDefaultValue(String bytes) {
|
||||
return new String(bytes.getBytes(ISO_8859_1), UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by generated code to construct default values for bytes
|
||||
* fields.
|
||||
* <p>
|
||||
* This is a lot like {@link #stringDefaultValue}, but for bytes fields.
|
||||
* In this case we only need the second of the two hacks -- allowing us to
|
||||
* embed raw bytes as a string literal with ISO-8859-1 encoding.
|
||||
* Helper called by generated code to construct default values for bytes fields.
|
||||
*
|
||||
* <p>This is a lot like {@link #stringDefaultValue}, but for bytes fields. In this case we only
|
||||
* need the second of the two hacks -- allowing us to embed raw bytes as a string literal with
|
||||
* ISO-8859-1 encoding.
|
||||
*/
|
||||
public static ByteString bytesDefaultValue(String bytes) {
|
||||
return ByteString.copyFrom(bytes.getBytes(ISO_8859_1));
|
||||
}
|
||||
/**
|
||||
* Helper called by generated code to construct default values for bytes
|
||||
* fields.
|
||||
* <p>
|
||||
* This is like {@link #bytesDefaultValue}, but returns a byte array.
|
||||
* Helper called by generated code to construct default values for bytes fields.
|
||||
*
|
||||
* <p>This is like {@link #bytesDefaultValue}, but returns a byte array.
|
||||
*/
|
||||
public static byte[] byteArrayDefaultValue(String bytes) {
|
||||
return bytes.getBytes(ISO_8859_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by generated code to construct default values for bytes
|
||||
* fields.
|
||||
* <p>
|
||||
* This is like {@link #bytesDefaultValue}, but returns a ByteBuffer.
|
||||
* Helper called by generated code to construct default values for bytes fields.
|
||||
*
|
||||
* <p>This is like {@link #bytesDefaultValue}, but returns a ByteBuffer.
|
||||
*/
|
||||
public static ByteBuffer byteBufferDefaultValue(String bytes) {
|
||||
return ByteBuffer.wrap(byteArrayDefaultValue(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ByteBuffer and copy all the content of {@code source}
|
||||
* ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and
|
||||
* capacity will be source.capacity(), and its position will be 0.
|
||||
* Note that the state of {@code source} ByteBuffer won't be changed.
|
||||
* Create a new ByteBuffer and copy all the content of {@code source} ByteBuffer to the new
|
||||
* ByteBuffer. The new ByteBuffer's limit and capacity will be source.capacity(), and its position
|
||||
* will be 0. Note that the state of {@code source} ByteBuffer won't be changed.
|
||||
*/
|
||||
public static ByteBuffer copyByteBuffer(ByteBuffer source) {
|
||||
// Make a duplicate of the source ByteBuffer and read data from the
|
||||
@ -162,29 +147,27 @@ public final class Internal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by generated code to determine if a byte array is a valid
|
||||
* UTF-8 encoded string such that the original bytes can be converted to
|
||||
* a String object and then back to a byte array round tripping the bytes
|
||||
* without loss. More precisely, returns {@code true} whenever:
|
||||
* <pre> {@code
|
||||
* Helper called by generated code to determine if a byte array is a valid UTF-8 encoded string
|
||||
* such that the original bytes can be converted to a String object and then back to a byte array
|
||||
* round tripping the bytes without loss. More precisely, returns {@code true} whenever:
|
||||
*
|
||||
* <pre>{@code
|
||||
* Arrays.equals(byteString.toByteArray(),
|
||||
* new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
|
||||
* }</pre>
|
||||
*
|
||||
* <p>This method rejects "overlong" byte sequences, as well as
|
||||
* 3-byte sequences that would map to a surrogate character, in
|
||||
* accordance with the restricted definition of UTF-8 introduced in
|
||||
* Unicode 3.1. Note that the UTF-8 decoder included in Oracle's
|
||||
* JDK has been modified to also reject "overlong" byte sequences,
|
||||
* but currently (2011) still accepts 3-byte surrogate character
|
||||
* <p>This method rejects "overlong" byte sequences, as well as 3-byte sequences that would map to
|
||||
* a surrogate character, in accordance with the restricted definition of UTF-8 introduced in
|
||||
* Unicode 3.1. Note that the UTF-8 decoder included in Oracle's JDK has been modified to also
|
||||
* reject "overlong" byte sequences, but currently (2011) still accepts 3-byte surrogate character
|
||||
* byte sequences.
|
||||
*
|
||||
* <p>See the Unicode Standard,<br>
|
||||
* Table 3-6. <em>UTF-8 Bit Distribution</em>,<br>
|
||||
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
|
||||
*
|
||||
* <p>As of 2011-02, this method simply returns the result of {@link
|
||||
* ByteString#isValidUtf8()}. Calling that method directly is preferred.
|
||||
* <p>As of 2011-02, this method simply returns the result of {@link ByteString#isValidUtf8()}.
|
||||
* Calling that method directly is preferred.
|
||||
*
|
||||
* @param byteString the string to check
|
||||
* @return whether the byte array is round trippable
|
||||
@ -193,42 +176,36 @@ public final class Internal {
|
||||
return byteString.isValidUtf8();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #isValidUtf8(ByteString)} but for byte arrays.
|
||||
*/
|
||||
/** Like {@link #isValidUtf8(ByteString)} but for byte arrays. */
|
||||
public static boolean isValidUtf8(byte[] byteArray) {
|
||||
return Utf8.isValidUtf8(byteArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the UTF-8 bytes of a string.
|
||||
*/
|
||||
/** Helper method to get the UTF-8 bytes of a string. */
|
||||
public static byte[] toByteArray(String value) {
|
||||
return value.getBytes(UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert a byte array to a string using UTF-8 encoding.
|
||||
*/
|
||||
/** Helper method to convert a byte array to a string using UTF-8 encoding. */
|
||||
public static String toStringUtf8(byte[] bytes) {
|
||||
return new String(bytes, UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an enum value or value descriptor, to be used in FieldSet.
|
||||
* The lite library stores enum values directly in FieldSets but the full
|
||||
* library stores EnumValueDescriptors in order to better support reflection.
|
||||
* Interface for an enum value or value descriptor, to be used in FieldSet. The lite library
|
||||
* stores enum values directly in FieldSets but the full library stores EnumValueDescriptors in
|
||||
* order to better support reflection.
|
||||
*/
|
||||
public interface EnumLite {
|
||||
int getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an object which maps integers to {@link EnumLite}s.
|
||||
* {@link Descriptors.EnumDescriptor} implements this interface by mapping
|
||||
* numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
|
||||
* every generated enum type has a static method internalGetValueMap() which
|
||||
* returns an implementation of this type that maps numbers to enum values.
|
||||
* Interface for an object which maps integers to {@link EnumLite}s. {@link
|
||||
* Descriptors.EnumDescriptor} implements this interface by mapping numbers to {@link
|
||||
* Descriptors.EnumValueDescriptor}s. Additionally, every generated enum type has a static method
|
||||
* internalGetValueMap() which returns an implementation of this type that maps numbers to enum
|
||||
* values.
|
||||
*/
|
||||
public interface EnumLiteMap<T extends EnumLite> {
|
||||
T findValueByNumber(int number);
|
||||
@ -241,6 +218,7 @@ public final class Internal {
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for longs.
|
||||
*
|
||||
* @see Long#hashCode()
|
||||
*/
|
||||
public static int hashLong(long n) {
|
||||
@ -248,8 +226,8 @@ public final class Internal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for
|
||||
* booleans.
|
||||
* Helper method for implementing {@link Message#hashCode()} for booleans.
|
||||
*
|
||||
* @see Boolean#hashCode()
|
||||
*/
|
||||
public static int hashBoolean(boolean b) {
|
||||
@ -258,19 +236,16 @@ public final class Internal {
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for enums.
|
||||
* <p>
|
||||
* This is needed because {@link java.lang.Enum#hashCode()} is final, but we
|
||||
* need to use the field number as the hash code to ensure compatibility
|
||||
* between statically and dynamically generated enum objects.
|
||||
*
|
||||
* <p>This is needed because {@link java.lang.Enum#hashCode()} is final, but we need to use the
|
||||
* field number as the hash code to ensure compatibility between statically and dynamically
|
||||
* generated enum objects.
|
||||
*/
|
||||
public static int hashEnum(EnumLite e) {
|
||||
return e.getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for
|
||||
* enum lists.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#hashCode()} for enum lists. */
|
||||
public static int hashEnumList(List<? extends EnumLite> list) {
|
||||
int hash = 1;
|
||||
for (EnumLite e : list) {
|
||||
@ -279,9 +254,7 @@ public final class Internal {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#equals(Object)} for bytes field.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#equals(Object)} for bytes field. */
|
||||
public static boolean equals(List<byte[]> a, List<byte[]> b) {
|
||||
if (a.size() != b.size()) return false;
|
||||
for (int i = 0; i < a.size(); ++i) {
|
||||
@ -292,9 +265,7 @@ public final class Internal {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for bytes field.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCode(List<byte[]> list) {
|
||||
int hash = 1;
|
||||
for (byte[] bytes : list) {
|
||||
@ -303,9 +274,7 @@ public final class Internal {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for bytes field.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCode(byte[] bytes) {
|
||||
// The hash code for a byte array should be the same as the hash code for a
|
||||
// ByteString with the same content. This is to ensure that the generated
|
||||
@ -313,10 +282,8 @@ public final class Internal {
|
||||
// based hashCode() method.
|
||||
return Internal.hashCode(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link LiteralByteString#hashCode()}.
|
||||
*/
|
||||
|
||||
/** Helper method for implementing {@link LiteralByteString#hashCode()}. */
|
||||
static int hashCode(byte[] bytes, int offset, int length) {
|
||||
// The hash code for a byte array should be the same as the hash code for a
|
||||
// ByteString with the same content. This is to ensure that the generated
|
||||
@ -326,20 +293,15 @@ public final class Internal {
|
||||
return h == 0 ? 1 : h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for continuously hashing bytes.
|
||||
*/
|
||||
/** Helper method for continuously hashing bytes. */
|
||||
static int partialHash(int h, byte[] bytes, int offset, int length) {
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
h = h * 31 + bytes[i];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#equals(Object)} for bytes
|
||||
* field.
|
||||
*/
|
||||
|
||||
/** Helper method for implementing {@link Message#equals(Object)} for bytes field. */
|
||||
public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
|
||||
if (a.capacity() != b.capacity()) {
|
||||
return false;
|
||||
@ -349,12 +311,8 @@ public final class Internal {
|
||||
return a.duplicate().clear().equals(b.duplicate().clear());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#equals(Object)} for bytes
|
||||
* field.
|
||||
*/
|
||||
public static boolean equalsByteBuffer(
|
||||
List<ByteBuffer> a, List<ByteBuffer> b) {
|
||||
/** Helper method for implementing {@link Message#equals(Object)} for bytes field. */
|
||||
public static boolean equalsByteBuffer(List<ByteBuffer> a, List<ByteBuffer> b) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
@ -366,10 +324,7 @@ public final class Internal {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for bytes
|
||||
* field.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCodeByteBuffer(List<ByteBuffer> list) {
|
||||
int hash = 1;
|
||||
for (ByteBuffer bytes : list) {
|
||||
@ -380,10 +335,7 @@ public final class Internal {
|
||||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for bytes
|
||||
* field.
|
||||
*/
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCodeByteBuffer(ByteBuffer bytes) {
|
||||
if (bytes.hasArray()) {
|
||||
// Fast path.
|
||||
@ -392,15 +344,15 @@ public final class Internal {
|
||||
} else {
|
||||
// Read the data into a temporary byte array before calculating the
|
||||
// hash value.
|
||||
final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE
|
||||
? DEFAULT_BUFFER_SIZE : bytes.capacity();
|
||||
final int bufferSize =
|
||||
bytes.capacity() > DEFAULT_BUFFER_SIZE ? DEFAULT_BUFFER_SIZE : bytes.capacity();
|
||||
final byte[] buffer = new byte[bufferSize];
|
||||
final ByteBuffer duplicated = bytes.duplicate();
|
||||
duplicated.clear();
|
||||
int h = bytes.capacity();
|
||||
while (duplicated.remaining() > 0) {
|
||||
final int length = duplicated.remaining() <= bufferSize ?
|
||||
duplicated.remaining() : bufferSize;
|
||||
final int length =
|
||||
duplicated.remaining() <= bufferSize ? duplicated.remaining() : bufferSize;
|
||||
duplicated.get(buffer, 0, length);
|
||||
h = partialHash(h, buffer, 0, length);
|
||||
}
|
||||
@ -414,8 +366,7 @@ public final class Internal {
|
||||
Method method = clazz.getMethod("getDefaultInstance");
|
||||
return (T) method.invoke(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to get default instance for " + clazz, e);
|
||||
throw new RuntimeException("Failed to get default instance for " + clazz, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,11 +374,8 @@ public final class Internal {
|
||||
/** An empty byte array constant used in generated code. */
|
||||
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
|
||||
/**
|
||||
* An empty byte array constant used in generated code.
|
||||
*/
|
||||
public static final ByteBuffer EMPTY_BYTE_BUFFER =
|
||||
ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
|
||||
/** An empty byte array constant used in generated code. */
|
||||
public static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
|
||||
|
||||
/** An empty coded input stream constant used in generated code. */
|
||||
public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
|
||||
@ -442,12 +390,10 @@ public final class Internal {
|
||||
/**
|
||||
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
|
||||
*
|
||||
* Protobuf internal. Used in protobuf generated code only.
|
||||
* <p>Protobuf internal. Used in protobuf generated code only.
|
||||
*/
|
||||
public static class ListAdapter<F, T> extends AbstractList<T> {
|
||||
/**
|
||||
* Convert individual elements of the List from F to T.
|
||||
*/
|
||||
/** Convert individual elements of the List from F to T. */
|
||||
public interface Converter<F, T> {
|
||||
T convert(F from);
|
||||
}
|
||||
@ -471,16 +417,12 @@ public final class Internal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap around a {@code Map<K, RealValue>} and provide a {@code Map<K, V>}
|
||||
* interface.
|
||||
*/
|
||||
/** Wrap around a {@code Map<K, RealValue>} and provide a {@code Map<K, V>} interface. */
|
||||
public static class MapAdapter<K, V, RealValue> extends AbstractMap<K, V> {
|
||||
/**
|
||||
* An interface used to convert between two types.
|
||||
*/
|
||||
/** An interface used to convert between two types. */
|
||||
public interface Converter<A, B> {
|
||||
B doForward(A object);
|
||||
|
||||
A doBackward(B object);
|
||||
}
|
||||
|
||||
@ -503,8 +445,7 @@ public final class Internal {
|
||||
private final Map<K, RealValue> realMap;
|
||||
private final Converter<RealValue, V> valueConverter;
|
||||
|
||||
public MapAdapter(Map<K, RealValue> realMap,
|
||||
Converter<RealValue, V> valueConverter) {
|
||||
public MapAdapter(Map<K, RealValue> realMap, Converter<RealValue, V> valueConverter) {
|
||||
this.realMap = realMap;
|
||||
this.valueConverter = valueConverter;
|
||||
}
|
||||
@ -535,6 +476,7 @@ public final class Internal {
|
||||
|
||||
private class SetAdapter extends AbstractSet<Map.Entry<K, V>> {
|
||||
private final Set<Map.Entry<K, RealValue>> realSet;
|
||||
|
||||
public SetAdapter(Set<Map.Entry<K, RealValue>> realSet) {
|
||||
this.realSet = realSet;
|
||||
}
|
||||
@ -553,8 +495,7 @@ public final class Internal {
|
||||
private class IteratorAdapter implements Iterator<Map.Entry<K, V>> {
|
||||
private final Iterator<Map.Entry<K, RealValue>> realIterator;
|
||||
|
||||
public IteratorAdapter(
|
||||
Iterator<Map.Entry<K, RealValue>> realIterator) {
|
||||
public IteratorAdapter(Iterator<Map.Entry<K, RealValue>> realIterator) {
|
||||
this.realIterator = realIterator;
|
||||
}
|
||||
|
||||
@ -593,8 +534,7 @@ public final class Internal {
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
RealValue oldValue = realEntry.setValue(
|
||||
valueConverter.doBackward(value));
|
||||
RealValue oldValue = realEntry.setValue(valueConverter.doBackward(value));
|
||||
if (oldValue == null) {
|
||||
return null;
|
||||
}
|
||||
@ -606,14 +546,14 @@ public final class Internal {
|
||||
/**
|
||||
* Extends {@link List} to add the capability to make the list immutable and inspect if it is
|
||||
* modifiable.
|
||||
* <p>
|
||||
* All implementations must support efficient random access.
|
||||
*
|
||||
* <p>All implementations must support efficient random access.
|
||||
*/
|
||||
public static interface ProtobufList<E> extends List<E>, RandomAccess {
|
||||
|
||||
/**
|
||||
* Makes this list immutable. All subsequent modifications will throw an
|
||||
* {@link UnsupportedOperationException}.
|
||||
* Makes this list immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
void makeImmutable();
|
||||
|
||||
@ -622,9 +562,7 @@ public final class Internal {
|
||||
*/
|
||||
boolean isModifiable();
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
ProtobufList<E> mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
@ -634,24 +572,16 @@ public final class Internal {
|
||||
*/
|
||||
public static interface IntList extends ProtobufList<Integer> {
|
||||
|
||||
/**
|
||||
* Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
|
||||
*/
|
||||
/** Like {@link #get(int)} but more efficient in that it doesn't box the returned value. */
|
||||
int getInt(int index);
|
||||
|
||||
/**
|
||||
* Like {@link #add(Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Object)} but more efficient in that it doesn't box the element. */
|
||||
void addInt(int element);
|
||||
|
||||
/**
|
||||
* Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
int setInt(int index, int element);
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
IntList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
@ -662,52 +592,36 @@ public final class Internal {
|
||||
*/
|
||||
public static interface BooleanList extends ProtobufList<Boolean> {
|
||||
|
||||
/**
|
||||
* Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
|
||||
*/
|
||||
/** Like {@link #get(int)} but more efficient in that it doesn't box the returned value. */
|
||||
boolean getBoolean(int index);
|
||||
|
||||
/**
|
||||
* Like {@link #add(Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Object)} but more efficient in that it doesn't box the element. */
|
||||
void addBoolean(boolean element);
|
||||
|
||||
/**
|
||||
* Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
boolean setBoolean(int index, boolean element);
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
BooleanList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Longs if
|
||||
* possible. Does not support null elements.
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Longs if possible.
|
||||
* Does not support null elements.
|
||||
*/
|
||||
public static interface LongList extends ProtobufList<Long> {
|
||||
|
||||
/**
|
||||
* Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
|
||||
*/
|
||||
/** Like {@link #get(int)} but more efficient in that it doesn't box the returned value. */
|
||||
long getLong(int index);
|
||||
|
||||
/**
|
||||
* Like {@link #add(Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Object)} but more efficient in that it doesn't box the element. */
|
||||
void addLong(long element);
|
||||
|
||||
/**
|
||||
* Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
long setLong(int index, long element);
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
LongList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
@ -718,24 +632,16 @@ public final class Internal {
|
||||
*/
|
||||
public static interface DoubleList extends ProtobufList<Double> {
|
||||
|
||||
/**
|
||||
* Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
|
||||
*/
|
||||
/** Like {@link #get(int)} but more efficient in that it doesn't box the returned value. */
|
||||
double getDouble(int index);
|
||||
|
||||
/**
|
||||
* Like {@link #add(Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Object)} but more efficient in that it doesn't box the element. */
|
||||
void addDouble(double element);
|
||||
|
||||
/**
|
||||
* Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
double setDouble(int index, double element);
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
DoubleList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
@ -746,24 +652,16 @@ public final class Internal {
|
||||
*/
|
||||
public static interface FloatList extends ProtobufList<Float> {
|
||||
|
||||
/**
|
||||
* Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
|
||||
*/
|
||||
/** Like {@link #get(int)} but more efficient in that it doesn't box the returned value. */
|
||||
float getFloat(int index);
|
||||
|
||||
/**
|
||||
* Like {@link #add(Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Object)} but more efficient in that it doesn't box the element. */
|
||||
void addFloat(float element);
|
||||
|
||||
/**
|
||||
* Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
float setFloat(int index, float element);
|
||||
|
||||
/**
|
||||
* Returns a mutable clone of this list with the specified capacity.
|
||||
*/
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
FloatList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ package com.google.protobuf;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thrown when a protocol message being parsed is invalid in some way,
|
||||
* e.g. it contains a malformed varint or a negative byte length.
|
||||
* Thrown when a protocol message being parsed is invalid in some way, e.g. it contains a malformed
|
||||
* varint or a negative byte length.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -55,28 +55,26 @@ public class InvalidProtocolBufferException extends IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches an unfinished message to the exception to support best-effort
|
||||
* parsing in {@code Parser} interface.
|
||||
* Attaches an unfinished message to the exception to support best-effort parsing in {@code
|
||||
* Parser} interface.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public InvalidProtocolBufferException setUnfinishedMessage(
|
||||
MessageLite unfinishedMessage) {
|
||||
public InvalidProtocolBufferException setUnfinishedMessage(MessageLite unfinishedMessage) {
|
||||
this.unfinishedMessage = unfinishedMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unfinished message attached to the exception, or null if
|
||||
* no message is attached.
|
||||
* Returns the unfinished message attached to the exception, or null if no message is attached.
|
||||
*/
|
||||
public MessageLite getUnfinishedMessage() {
|
||||
return unfinishedMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwraps the underlying {@link IOException} if this exception was caused by an I/O
|
||||
* problem. Otherwise, returns {@code this}.
|
||||
* Unwraps the underlying {@link IOException} if this exception was caused by an I/O problem.
|
||||
* Otherwise, returns {@code this}.
|
||||
*/
|
||||
public IOException unwrapIOException() {
|
||||
return getCause() instanceof IOException ? (IOException) getCause() : this;
|
||||
@ -84,41 +82,36 @@ public class InvalidProtocolBufferException extends IOException {
|
||||
|
||||
static InvalidProtocolBufferException truncatedMessage() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"While parsing a protocol message, the input ended unexpectedly " +
|
||||
"in the middle of a field. This could mean either that the " +
|
||||
"input has been truncated or that an embedded message " +
|
||||
"misreported its own length.");
|
||||
"While parsing a protocol message, the input ended unexpectedly "
|
||||
+ "in the middle of a field. This could mean either that the "
|
||||
+ "input has been truncated or that an embedded message "
|
||||
+ "misreported its own length.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException negativeSize() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"CodedInputStream encountered an embedded string or message " +
|
||||
"which claimed to have negative size.");
|
||||
"CodedInputStream encountered an embedded string or message "
|
||||
+ "which claimed to have negative size.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException malformedVarint() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"CodedInputStream encountered a malformed varint.");
|
||||
return new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidTag() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message contained an invalid tag (zero).");
|
||||
return new InvalidProtocolBufferException("Protocol message contained an invalid tag (zero).");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidEndTag() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message end-group tag did not match expected tag.");
|
||||
"Protocol message end-group tag did not match expected tag.");
|
||||
}
|
||||
|
||||
static InvalidWireTypeException invalidWireType() {
|
||||
return new InvalidWireTypeException(
|
||||
"Protocol message tag had invalid wire type.");
|
||||
return new InvalidWireTypeException("Protocol message tag had invalid wire type.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception indicating that and unexpected wire type was encountered for a field.
|
||||
*/
|
||||
/** Exception indicating that and unexpected wire type was encountered for a field. */
|
||||
@ExperimentalApi
|
||||
public static class InvalidWireTypeException extends InvalidProtocolBufferException {
|
||||
private static final long serialVersionUID = 3283890091615336259L;
|
||||
@ -130,14 +123,14 @@ public class InvalidProtocolBufferException extends IOException {
|
||||
|
||||
static InvalidProtocolBufferException recursionLimitExceeded() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message had too many levels of nesting. May be malicious. " +
|
||||
"Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
|
||||
"Protocol message had too many levels of nesting. May be malicious. "
|
||||
+ "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException sizeLimitExceeded() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message was too large. May be malicious. " +
|
||||
"Use CodedInputStream.setSizeLimit() to increase the size limit.");
|
||||
"Protocol message was too large. May be malicious. "
|
||||
+ "Use CodedInputStream.setSizeLimit() to increase the size limit.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException parseFailure() {
|
||||
|
@ -34,12 +34,12 @@ import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* LazyField encapsulates the logic of lazily parsing message fields. It stores
|
||||
* the message in a ByteString initially and then parse it on-demand.
|
||||
* LazyField encapsulates the logic of lazily parsing message fields. It stores the message in a
|
||||
* ByteString initially and then parse it on-demand.
|
||||
*
|
||||
* Most of key methods are implemented in {@link LazyFieldLite} but this class
|
||||
* can contain default instance of the message to provide {@code hashCode()},
|
||||
* {@code euqals()} and {@code toString()}.
|
||||
* <p>Most of key methods are implemented in {@link LazyFieldLite} but this class can contain
|
||||
* default instance of the message to provide {@code hashCode()}, {@code euqals()} and {@code
|
||||
* toString()}.
|
||||
*
|
||||
* @author xiangl@google.com (Xiang Li)
|
||||
*/
|
||||
@ -51,8 +51,8 @@ public class LazyField extends LazyFieldLite {
|
||||
*/
|
||||
private final MessageLite defaultInstance;
|
||||
|
||||
public LazyField(MessageLite defaultInstance,
|
||||
ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
public LazyField(
|
||||
MessageLite defaultInstance, ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
super(extensionRegistry, bytes);
|
||||
|
||||
this.defaultInstance = defaultInstance;
|
||||
@ -85,8 +85,8 @@ public class LazyField extends LazyFieldLite {
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* LazyEntry and LazyIterator are used to encapsulate the LazyField, when
|
||||
* users iterate all fields from FieldSet.
|
||||
* LazyEntry and LazyIterator are used to encapsulate the LazyField, when users iterate all fields
|
||||
* from FieldSet.
|
||||
*/
|
||||
static class LazyEntry<K> implements Entry<K, Object> {
|
||||
private Entry<K, LazyField> entry;
|
||||
@ -118,7 +118,7 @@ public class LazyField extends LazyFieldLite {
|
||||
if (!(value instanceof MessageLite)) {
|
||||
throw new IllegalArgumentException(
|
||||
"LazyField now only used for MessageSet, "
|
||||
+ "and the value of MessageSet must be an instance of MessageLite");
|
||||
+ "and the value of MessageSet must be an instance of MessageLite");
|
||||
}
|
||||
return entry.getValue().setValue((MessageLite) value);
|
||||
}
|
||||
|
@ -33,23 +33,23 @@ package com.google.protobuf;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
|
||||
* the message in a ByteString initially and then parses it on-demand.
|
||||
* LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores the message in a
|
||||
* ByteString initially and then parses it on-demand.
|
||||
*
|
||||
* LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
|
||||
* <p>LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
|
||||
* LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit
|
||||
* synchronization is needed under read/write situations.
|
||||
*
|
||||
* When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered
|
||||
* to be immutable and none of the setter methods in its API are expected to be invoked. All of the
|
||||
* getters are expected to be thread-safe. When used in the context of a MessageLite.Builder,
|
||||
* setters can be invoked, but there is no guarantee of thread safety.
|
||||
*
|
||||
* TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
|
||||
* <p>When a LazyFieldLite is used in the context of a MessageLite object, its behavior is
|
||||
* considered to be immutable and none of the setter methods in its API are expected to be invoked.
|
||||
* All of the getters are expected to be thread-safe. When used in the context of a
|
||||
* MessageLite.Builder, setters can be invoked, but there is no guarantee of thread safety.
|
||||
*
|
||||
* <p>TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
|
||||
* into a separate builder class to allow us to give stronger compile-time guarantees.
|
||||
*
|
||||
* This class is internal implementation detail of the protobuf library, so you don't need to use it
|
||||
* directly.
|
||||
* <p>This class is internal implementation detail of the protobuf library, so you don't need to use
|
||||
* it directly.
|
||||
*
|
||||
* @author xiangl@google.com (Xiang Li)
|
||||
*/
|
||||
@ -57,23 +57,27 @@ public class LazyFieldLite {
|
||||
private static final ExtensionRegistryLite EMPTY_REGISTRY =
|
||||
ExtensionRegistryLite.getEmptyRegistry();
|
||||
|
||||
/**
|
||||
/*
|
||||
* The value associated with the LazyFieldLite object is stored in one or more of the following
|
||||
* three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as
|
||||
* follows.
|
||||
* 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
|
||||
* this state while the value for the object has not yet been parsed.
|
||||
* 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
|
||||
* some caller needs to access the value (by invoking getValue()).
|
||||
* 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
|
||||
* recomputing the ByteString representation on each call. Instead, when the value is parsed
|
||||
* from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since
|
||||
* that is the ByteString representation of value).
|
||||
* 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
|
||||
* delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
|
||||
* LazyFieldLite.toByteString().
|
||||
*
|
||||
* Given the above conditions, any caller that needs a serialized representation of this object
|
||||
* 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
|
||||
* this state while the value for the object has not yet been parsed.
|
||||
*
|
||||
* 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
|
||||
* some caller needs to access the value (by invoking getValue()).
|
||||
*
|
||||
* 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
|
||||
* recomputing the ByteString representation on each call. Instead, when the value is parsed from
|
||||
* delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since that is
|
||||
* the ByteString representation of value).
|
||||
*
|
||||
* 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
|
||||
* delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
|
||||
* LazyFieldLite.toByteString().
|
||||
*
|
||||
* <p>Given the above conditions, any caller that needs a serialized representation of this object
|
||||
* must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it
|
||||
* directly; if both of those are null, it can look at the parsed value field. Similarly, any
|
||||
* caller that needs a parsed value must first check if the value field is already non-null, if
|
||||
@ -84,16 +88,16 @@ public class LazyFieldLite {
|
||||
* A delayed-parsed version of the contents of this field. When this field is non-null, then the
|
||||
* "value" field is allowed to be null until the time that the value needs to be read.
|
||||
*
|
||||
* When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null.
|
||||
* {@code value} and {@code memoizedBytes} will be initialized lazily.
|
||||
* <p>When delayedBytes is non-null then {@code extensionRegistry} is required to also be
|
||||
* non-null. {@code value} and {@code memoizedBytes} will be initialized lazily.
|
||||
*/
|
||||
private ByteString delayedBytes;
|
||||
|
||||
/**
|
||||
* An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It
|
||||
* is only guaranteed to be non-null if this message was initialized using bytes and an
|
||||
* {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has
|
||||
* been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
|
||||
* is only guaranteed to be non-null if this message was initialized using bytes and an {@code
|
||||
* ExtensionRegistry}. If it directly had a value set then it will be null, unless it has been
|
||||
* merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
|
||||
*/
|
||||
private ExtensionRegistryLite extensionRegistry;
|
||||
|
||||
@ -105,25 +109,20 @@ public class LazyFieldLite {
|
||||
|
||||
/**
|
||||
* The memoized bytes for {@code value}. This is an optimization for the toByteString() method to
|
||||
* not have to recompute its return-value on each invocation.
|
||||
* TODO(yatin): Figure out whether this optimization is actually necessary.
|
||||
* not have to recompute its return-value on each invocation. TODO(yatin): Figure out whether this
|
||||
* optimization is actually necessary.
|
||||
*/
|
||||
private volatile ByteString memoizedBytes;
|
||||
|
||||
/**
|
||||
* Constructs a LazyFieldLite with bytes that will be parsed lazily.
|
||||
*/
|
||||
/** Constructs a LazyFieldLite with bytes that will be parsed lazily. */
|
||||
public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
checkArguments(extensionRegistry, bytes);
|
||||
this.extensionRegistry = extensionRegistry;
|
||||
this.delayedBytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
|
||||
*/
|
||||
public LazyFieldLite() {
|
||||
}
|
||||
/** Constructs a LazyFieldLite with no contents, and no ability to parse extensions. */
|
||||
public LazyFieldLite() {}
|
||||
|
||||
/**
|
||||
* Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse
|
||||
@ -140,13 +139,13 @@ public class LazyFieldLite {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (!(o instanceof LazyFieldLite)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LazyFieldLite other = (LazyFieldLite) o;
|
||||
|
||||
|
||||
// Lazy fields do not work well with equals... If both are delayedBytes, we do not have a
|
||||
// mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an
|
||||
// actual message (if necessary) and call equals on the message itself. This implies that two
|
||||
@ -163,7 +162,7 @@ public class LazyFieldLite {
|
||||
return getValue(value2.getDefaultInstanceForType()).equals(value2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// We can't provide a memoizable hash code for lazy fields. The byte strings may have different
|
||||
@ -171,7 +170,7 @@ public class LazyFieldLite {
|
||||
// a message here if we were not already holding a value.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether this LazyFieldLite instance represents the default instance of this type.
|
||||
*/
|
||||
@ -183,8 +182,8 @@ public class LazyFieldLite {
|
||||
/**
|
||||
* Clears the value state of this instance.
|
||||
*
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed
|
||||
* under read/write situations.
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write
|
||||
* situations.
|
||||
*/
|
||||
public void clear() {
|
||||
// Don't clear the ExtensionRegistry. It might prove useful later on when merging in another
|
||||
@ -198,8 +197,8 @@ public class LazyFieldLite {
|
||||
/**
|
||||
* Overrides the contents of this LazyField.
|
||||
*
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed
|
||||
* under read/write situations.
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write
|
||||
* situations.
|
||||
*/
|
||||
public void set(LazyFieldLite other) {
|
||||
this.delayedBytes = other.delayedBytes;
|
||||
@ -218,7 +217,7 @@ public class LazyFieldLite {
|
||||
* Returns message instance. It may do some thread-safe delayed parsing of bytes.
|
||||
*
|
||||
* @param defaultInstance its message's default instance. It's also used to get parser for the
|
||||
* message type.
|
||||
* message type.
|
||||
*/
|
||||
public MessageLite getValue(MessageLite defaultInstance) {
|
||||
ensureInitialized(defaultInstance);
|
||||
@ -228,8 +227,8 @@ public class LazyFieldLite {
|
||||
/**
|
||||
* Sets the value of the instance and returns the old value without delay parsing anything.
|
||||
*
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed
|
||||
* under read/write situations.
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write
|
||||
* situations.
|
||||
*/
|
||||
public MessageLite setValue(MessageLite value) {
|
||||
MessageLite originalValue = this.value;
|
||||
@ -244,8 +243,8 @@ public class LazyFieldLite {
|
||||
* contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this
|
||||
* field will copy over that {@code ExtensionRegistry}.
|
||||
*
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed
|
||||
* under read/write situations.
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write
|
||||
* situations.
|
||||
*/
|
||||
public void merge(LazyFieldLite other) {
|
||||
if (other.containsDefaultInstance()) {
|
||||
@ -287,12 +286,12 @@ public class LazyFieldLite {
|
||||
// At this point we have two fully parsed messages.
|
||||
setValue(this.value.toBuilder().mergeFrom(other.value).build());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merges another instance's contents from a stream.
|
||||
*
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed
|
||||
* under read/write situations.
|
||||
* <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write
|
||||
* situations.
|
||||
*/
|
||||
public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
@ -339,9 +338,7 @@ public class LazyFieldLite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this field with bytes to delay-parse.
|
||||
*/
|
||||
/** Sets this field with bytes to delay-parse. */
|
||||
public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
|
||||
checkArguments(extensionRegistry, bytes);
|
||||
this.delayedBytes = bytes;
|
||||
@ -351,9 +348,8 @@ public class LazyFieldLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the optional field can be duplicated at the end of serialized
|
||||
* bytes, which will make the serialized size changed after LazyField
|
||||
* parsed. Be careful when using this method.
|
||||
* Due to the optional field can be duplicated at the end of serialized bytes, which will make the
|
||||
* serialized size changed after LazyField parsed. Be careful when using this method.
|
||||
*/
|
||||
public int getSerializedSize() {
|
||||
// We *must* return delayed bytes size if it was ever set because the dependent messages may
|
||||
@ -369,9 +365,7 @@ public class LazyFieldLite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BytesString for this field in a thread-safe way.
|
||||
*/
|
||||
/** Returns a BytesString for this field in a thread-safe way. */
|
||||
public ByteString toByteString() {
|
||||
if (memoizedBytes != null) {
|
||||
return memoizedBytes;
|
||||
@ -395,9 +389,7 @@ public class LazyFieldLite {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Might lazily parse the bytes that were previously passed in. Is thread-safe.
|
||||
*/
|
||||
/** Might lazily parse the bytes that were previously passed in. Is thread-safe. */
|
||||
protected void ensureInitialized(MessageLite defaultInstance) {
|
||||
if (value != null) {
|
||||
return;
|
||||
@ -409,8 +401,8 @@ public class LazyFieldLite {
|
||||
try {
|
||||
if (delayedBytes != null) {
|
||||
// The extensionRegistry shouldn't be null here since we have delayedBytes.
|
||||
MessageLite parsedValue = defaultInstance.getParserForType()
|
||||
.parseFrom(delayedBytes, extensionRegistry);
|
||||
MessageLite parsedValue =
|
||||
defaultInstance.getParserForType().parseFrom(delayedBytes, extensionRegistry);
|
||||
this.value = parsedValue;
|
||||
this.memoizedBytes = delayedBytes;
|
||||
} else {
|
||||
@ -426,7 +418,6 @@ public class LazyFieldLite {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
if (extensionRegistry == null) {
|
||||
throw new NullPointerException("found null ExtensionRegistry");
|
||||
|
@ -39,26 +39,22 @@ import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link LazyStringList} that wraps an ArrayList. Each
|
||||
* element is one of String, ByteString, or byte[]. It caches the last one
|
||||
* requested which is most likely the one needed next. This minimizes memory
|
||||
* usage while satisfying the most common use cases.
|
||||
* <p>
|
||||
* <strong>Note that this implementation is not synchronized.</strong>
|
||||
* If multiple threads access an <tt>ArrayList</tt> instance concurrently,
|
||||
* and at least one of the threads modifies the list structurally, it
|
||||
* <i>must</i> be synchronized externally. (A structural modification is
|
||||
* any operation that adds or deletes one or more elements, or explicitly
|
||||
* resizes the backing array; merely setting the value of an element is not
|
||||
* a structural modification.) This is typically accomplished by
|
||||
* synchronizing on some object that naturally encapsulates the list.
|
||||
* <p>
|
||||
* If the implementation is accessed via concurrent reads, this is thread safe.
|
||||
* Conversions are done in a thread safe manner. It's possible that the
|
||||
* conversion may happen more than once if two threads attempt to access the
|
||||
* same element and the modifications were not visible to each other, but this
|
||||
* will not result in any corruption of the list or change in behavior other
|
||||
* than performance.
|
||||
* An implementation of {@link LazyStringList} that wraps an ArrayList. Each element is one of
|
||||
* String, ByteString, or byte[]. It caches the last one requested which is most likely the one
|
||||
* needed next. This minimizes memory usage while satisfying the most common use cases.
|
||||
*
|
||||
* <p><strong>Note that this implementation is not synchronized.</strong> If multiple threads access
|
||||
* an <tt>ArrayList</tt> instance concurrently, and at least one of the threads modifies the list
|
||||
* structurally, it <i>must</i> be synchronized externally. (A structural modification is any
|
||||
* operation that adds or deletes one or more elements, or explicitly resizes the backing array;
|
||||
* merely setting the value of an element is not a structural modification.) This is typically
|
||||
* accomplished by synchronizing on some object that naturally encapsulates the list.
|
||||
*
|
||||
* <p>If the implementation is accessed via concurrent reads, this is thread safe. Conversions are
|
||||
* done in a thread safe manner. It's possible that the conversion may happen more than once if two
|
||||
* threads attempt to access the same element and the modifications were not visible to each other,
|
||||
* but this will not result in any corruption of the list or change in behavior other than
|
||||
* performance.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@ -66,6 +62,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
implements LazyStringList, RandomAccess {
|
||||
|
||||
private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -177,8 +174,8 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
ensureIsMutable();
|
||||
// When copying from another LazyStringList, directly copy the underlying
|
||||
// elements rather than forcing each element to be decoded to a String.
|
||||
Collection<?> collection = c instanceof LazyStringList
|
||||
? ((LazyStringList) c).getUnderlyingElements() : c;
|
||||
Collection<?> collection =
|
||||
c instanceof LazyStringList ? ((LazyStringList) c).getUnderlyingElements() : c;
|
||||
boolean ret = list.addAll(index, collection);
|
||||
modCount++;
|
||||
return ret;
|
||||
@ -324,8 +321,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
}
|
||||
}
|
||||
|
||||
private static class ByteArrayListView extends AbstractList<byte[]>
|
||||
implements RandomAccess {
|
||||
private static class ByteArrayListView extends AbstractList<byte[]> implements RandomAccess {
|
||||
private final LazyStringArrayList list;
|
||||
|
||||
ByteArrayListView(LazyStringArrayList list) {
|
||||
@ -368,8 +364,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
return new ByteArrayListView(this);
|
||||
}
|
||||
|
||||
private static class ByteStringListView extends AbstractList<ByteString>
|
||||
implements RandomAccess {
|
||||
private static class ByteStringListView extends AbstractList<ByteString> implements RandomAccess {
|
||||
private final LazyStringArrayList list;
|
||||
|
||||
ByteStringListView(LazyStringArrayList list) {
|
||||
@ -419,5 +414,4 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,14 +34,12 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An interface extending {@code List<String>} that also provides access to the
|
||||
* items of the list as UTF8-encoded ByteString or byte[] objects. This is
|
||||
* used by the protocol buffer implementation to support lazily converting bytes
|
||||
* parsed over the wire to String objects until needed and also increases the
|
||||
* efficiency of serialization if the String was never requested as the
|
||||
* ByteString or byte[] is already cached. The ByteString methods are used in
|
||||
* immutable API only and byte[] methods used in mutable API only for they use
|
||||
* different representations for string/bytes fields.
|
||||
* An interface extending {@code List<String>} that also provides access to the items of the list as
|
||||
* UTF8-encoded ByteString or byte[] objects. This is used by the protocol buffer implementation to
|
||||
* support lazily converting bytes parsed over the wire to String objects until needed and also
|
||||
* increases the efficiency of serialization if the String was never requested as the ByteString or
|
||||
* byte[] is already cached. The ByteString methods are used in immutable API only and byte[]
|
||||
* methods used in mutable API only for they use different representations for string/bytes fields.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@ -52,19 +50,19 @@ public interface LazyStringList extends ProtocolStringList {
|
||||
*
|
||||
* @param index index of the element to return
|
||||
* @return the element at the specified position in this list
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
* @throws IndexOutOfBoundsException if the index is out of range ({@code index < 0 || index >=
|
||||
* size()})
|
||||
*/
|
||||
ByteString getByteString(int index);
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this list as an Object
|
||||
* that will either be a String or a ByteString.
|
||||
* Returns the element at the specified position in this list as an Object that will either be a
|
||||
* String or a ByteString.
|
||||
*
|
||||
* @param index index of the element to return
|
||||
* @return the element at the specified position in this list
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
* @throws IndexOutOfBoundsException if the index is out of range ({@code index < 0 || index >=
|
||||
* size()})
|
||||
*/
|
||||
Object getRaw(int index);
|
||||
|
||||
@ -73,99 +71,91 @@ public interface LazyStringList extends ProtocolStringList {
|
||||
*
|
||||
* @param index index of the element to return
|
||||
* @return the element at the specified position in this list
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
* @throws IndexOutOfBoundsException if the index is out of range ({@code index < 0 || index >=
|
||||
* size()})
|
||||
*/
|
||||
byte[] getByteArray(int index);
|
||||
|
||||
/**
|
||||
* Appends the specified element to the end of this list (optional
|
||||
* operation).
|
||||
* Appends the specified element to the end of this list (optional operation).
|
||||
*
|
||||
* @param element element to be appended to this list
|
||||
* @throws UnsupportedOperationException if the <tt>add</tt> operation
|
||||
* is not supported by this list
|
||||
* @throws UnsupportedOperationException if the <tt>add</tt> operation is not supported by this
|
||||
* list
|
||||
*/
|
||||
void add(ByteString element);
|
||||
|
||||
/**
|
||||
* Appends the specified element to the end of this list (optional
|
||||
* operation).
|
||||
* Appends the specified element to the end of this list (optional operation).
|
||||
*
|
||||
* @param element element to be appended to this list
|
||||
* @throws UnsupportedOperationException if the <tt>add</tt> operation
|
||||
* is not supported by this list
|
||||
* @throws UnsupportedOperationException if the <tt>add</tt> operation is not supported by this
|
||||
* list
|
||||
*/
|
||||
void add(byte[] element);
|
||||
|
||||
/**
|
||||
* Replaces the element at the specified position in this list with the
|
||||
* specified element (optional operation).
|
||||
* Replaces the element at the specified position in this list with the specified element
|
||||
* (optional operation).
|
||||
*
|
||||
* @param index index of the element to replace
|
||||
* @param element the element to be stored at the specified position
|
||||
* @throws UnsupportedOperationException if the <tt>set</tt> operation
|
||||
* is not supported by this list
|
||||
* IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
* @throws UnsupportedOperationException if the <tt>set</tt> operation is not supported by this
|
||||
* list IndexOutOfBoundsException if the index is out of range ({@code index < 0 || index >=
|
||||
* size()})
|
||||
*/
|
||||
void set(int index, ByteString element);
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the element at the specified position in this list with the
|
||||
* specified element (optional operation).
|
||||
* Replaces the element at the specified position in this list with the specified element
|
||||
* (optional operation).
|
||||
*
|
||||
* @param index index of the element to replace
|
||||
* @param element the element to be stored at the specified position
|
||||
* @throws UnsupportedOperationException if the <tt>set</tt> operation
|
||||
* is not supported by this list
|
||||
* IndexOutOfBoundsException if the index is out of range
|
||||
* ({@code index < 0 || index >= size()})
|
||||
* @throws UnsupportedOperationException if the <tt>set</tt> operation is not supported by this
|
||||
* list IndexOutOfBoundsException if the index is out of range ({@code index < 0 || index >=
|
||||
* size()})
|
||||
*/
|
||||
void set(int index, byte[] element);
|
||||
|
||||
/**
|
||||
* Appends all elements in the specified ByteString collection to the end of
|
||||
* this list.
|
||||
* Appends all elements in the specified ByteString collection to the end of this list.
|
||||
*
|
||||
* @param c collection whose elements are to be added to this list
|
||||
* @return true if this list changed as a result of the call
|
||||
* @throws UnsupportedOperationException if the <tt>addAllByteString</tt>
|
||||
* operation is not supported by this list
|
||||
* @throws UnsupportedOperationException if the <tt>addAllByteString</tt> operation is not
|
||||
* supported by this list
|
||||
*/
|
||||
boolean addAllByteString(Collection<? extends ByteString> c);
|
||||
|
||||
/**
|
||||
* Appends all elements in the specified byte[] collection to the end of
|
||||
* this list.
|
||||
* Appends all elements in the specified byte[] collection to the end of this list.
|
||||
*
|
||||
* @param c collection whose elements are to be added to this list
|
||||
* @return true if this list changed as a result of the call
|
||||
* @throws UnsupportedOperationException if the <tt>addAllByteArray</tt>
|
||||
* operation is not supported by this list
|
||||
* @throws UnsupportedOperationException if the <tt>addAllByteArray</tt> operation is not
|
||||
* supported by this list
|
||||
*/
|
||||
boolean addAllByteArray(Collection<byte[]> c);
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable List of the underlying elements, each of which is
|
||||
* either a {@code String} or its equivalent UTF-8 encoded {@code ByteString}
|
||||
* or byte[]. It is an error for the caller to modify the returned
|
||||
* List, and attempting to do so will result in an
|
||||
* {@link UnsupportedOperationException}.
|
||||
* Returns an unmodifiable List of the underlying elements, each of which is either a {@code
|
||||
* String} or its equivalent UTF-8 encoded {@code ByteString} or byte[]. It is an error for the
|
||||
* caller to modify the returned List, and attempting to do so will result in an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
List<?> getUnderlyingElements();
|
||||
|
||||
/**
|
||||
* Merges all elements from another LazyStringList into this one. This method
|
||||
* differs from {@link #addAll(Collection)} on that underlying byte arrays are
|
||||
* copied instead of reference shared. Immutable API doesn't need to use this
|
||||
* method as byte[] is not used there at all.
|
||||
* Merges all elements from another LazyStringList into this one. This method differs from {@link
|
||||
* #addAll(Collection)} on that underlying byte arrays are copied instead of reference shared.
|
||||
* Immutable API doesn't need to use this method as byte[] is not used there at all.
|
||||
*/
|
||||
void mergeFrom(LazyStringList other);
|
||||
|
||||
/**
|
||||
* Returns a mutable view of this list. Changes to the view will be made into
|
||||
* the original list. This method is used in mutable API only.
|
||||
* Returns a mutable view of this list. Changes to the view will be made into the original list.
|
||||
* This method is used in mutable API only.
|
||||
*/
|
||||
List<byte[]> asByteArrayList();
|
||||
|
||||
|
@ -42,11 +42,11 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class LongArrayList
|
||||
extends AbstractProtobufList<Long>
|
||||
final class LongArrayList extends AbstractProtobufList<Long>
|
||||
implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final LongArrayList EMPTY_LIST = new LongArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
@ -55,9 +55,7 @@ final class LongArrayList
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing store for the list.
|
||||
*/
|
||||
/** The backing store for the list. */
|
||||
private long[] array;
|
||||
|
||||
/**
|
||||
@ -66,16 +64,13 @@ final class LongArrayList
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code LongArrayList} with default capacity.
|
||||
*/
|
||||
/** Constructs a new mutable {@code LongArrayList} with default capacity. */
|
||||
LongArrayList() {
|
||||
this(new long[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new mutable {@code LongArrayList}
|
||||
* containing the same elements as {@code other}.
|
||||
* Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
|
||||
*/
|
||||
private LongArrayList(long[] other, int size) {
|
||||
array = other;
|
||||
@ -169,17 +164,13 @@ final class LongArrayList
|
||||
addLong(index, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(Long)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(Long)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addLong(long element) {
|
||||
addLong(size, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #add(int, Long)} but more efficient in that it doesn't box the element.
|
||||
*/
|
||||
/** Like {@link #add(int, Long)} but more efficient in that it doesn't box the element. */
|
||||
private void addLong(int index, long element) {
|
||||
ensureIsMutable();
|
||||
if (index < 0 || index > size) {
|
||||
|
@ -41,11 +41,11 @@ 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.
|
||||
* <p>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.
|
||||
* <p>Protobuf internal. Users shouldn't use this class.
|
||||
*/
|
||||
public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
@ -61,15 +61,16 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
WireFormat.FieldType valueType) {
|
||||
super(keyType, defaultInstance.key, valueType, defaultInstance.value);
|
||||
this.descriptor = descriptor;
|
||||
this.parser = new AbstractParser<MapEntry<K, V>>() {
|
||||
this.parser =
|
||||
new AbstractParser<MapEntry<K, V>>() {
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> parsePartialFrom(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public MapEntry<K, V> parsePartialFrom(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +81,10 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
/** Create a default MapEntry instance. */
|
||||
private MapEntry(
|
||||
Descriptor descriptor,
|
||||
WireFormat.FieldType keyType, K defaultKey,
|
||||
WireFormat.FieldType valueType, V defaultValue) {
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
this.key = defaultKey;
|
||||
this.value = defaultValue;
|
||||
this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
|
||||
@ -97,9 +100,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
/** Parsing constructor. */
|
||||
private MapEntry(
|
||||
Metadata<K, V> metadata,
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
Metadata<K, V> metadata, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
this.metadata = metadata;
|
||||
@ -114,17 +115,17 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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);
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
return new MapEntry<K, V>(descriptor, keyType, defaultKey, valueType, defaultValue);
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
@ -197,14 +198,17 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
private void checkFieldDescriptor(FieldDescriptor field) {
|
||||
if (field.getContainingType() != metadata.descriptor) {
|
||||
throw new RuntimeException(
|
||||
"Wrong FieldDescriptor \"" + field.getFullName()
|
||||
+ "\" used in message \"" + metadata.descriptor.getFullName());
|
||||
"Wrong FieldDescriptor \""
|
||||
+ field.getFullName()
|
||||
+ "\" used in message \""
|
||||
+ metadata.descriptor.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);;
|
||||
checkFieldDescriptor(field);
|
||||
;
|
||||
// A MapEntry always contains two fields.
|
||||
return true;
|
||||
}
|
||||
@ -215,22 +219,19 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
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);
|
||||
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.");
|
||||
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.");
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -238,11 +239,8 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
return UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to create {@link MapEntry} messages.
|
||||
*/
|
||||
public static class Builder<K, V>
|
||||
extends AbstractMessage.Builder<Builder<K, V>> {
|
||||
/** Builder to create {@link MapEntry} messages. */
|
||||
public static class Builder<K, V> extends AbstractMessage.Builder<Builder<K, V>> {
|
||||
private final Metadata<K, V> metadata;
|
||||
private K key;
|
||||
private V value;
|
||||
@ -315,20 +313,21 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
private void checkFieldDescriptor(FieldDescriptor field) {
|
||||
if (field.getContainingType() != metadata.descriptor) {
|
||||
throw new RuntimeException(
|
||||
"Wrong FieldDescriptor \"" + field.getFullName()
|
||||
+ "\" used in message \"" + metadata.descriptor.getFullName());
|
||||
"Wrong FieldDescriptor \""
|
||||
+ field.getFullName()
|
||||
+ "\" used in message \""
|
||||
+ metadata.descriptor.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message.Builder newBuilderForField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(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.");
|
||||
if (field.getNumber() != 2 || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new RuntimeException("\"" + field.getFullName() + "\" is not a message value field.");
|
||||
}
|
||||
return ((Message) value).newBuilderForType();
|
||||
}
|
||||
@ -369,16 +368,13 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
}
|
||||
|
||||
@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.");
|
||||
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.");
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -427,14 +423,12 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
throw new RuntimeException(
|
||||
"There is no repeated field in a map entry message.");
|
||||
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.");
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -455,7 +449,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the metadata only for experimental runtime. */
|
||||
final Metadata<K, V> getMetadata() {
|
||||
return metadata;
|
||||
|
@ -37,11 +37,10 @@ import java.util.Map;
|
||||
/**
|
||||
* 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.
|
||||
* <p>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.
|
||||
* <p>Protobuf internal. Users shouldn't use.
|
||||
*/
|
||||
public class MapEntryLite<K, V> {
|
||||
|
||||
@ -52,8 +51,10 @@ public class MapEntryLite<K, V> {
|
||||
public final V defaultValue;
|
||||
|
||||
public Metadata(
|
||||
WireFormat.FieldType keyType, K defaultKey,
|
||||
WireFormat.FieldType valueType, V defaultValue) {
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
this.keyType = keyType;
|
||||
this.defaultKey = defaultKey;
|
||||
this.valueType = valueType;
|
||||
@ -70,8 +71,7 @@ public class MapEntryLite<K, V> {
|
||||
|
||||
/** Creates a default MapEntryLite message instance. */
|
||||
private MapEntryLite(
|
||||
WireFormat.FieldType keyType, K defaultKey,
|
||||
WireFormat.FieldType valueType, V defaultValue) {
|
||||
WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue) {
|
||||
this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultValue);
|
||||
this.key = defaultKey;
|
||||
this.value = defaultValue;
|
||||
@ -95,16 +95,13 @@ public class MapEntryLite<K, V> {
|
||||
/**
|
||||
* 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.
|
||||
* <p>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);
|
||||
WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue) {
|
||||
return new MapEntryLite<K, V>(keyType, defaultKey, valueType, defaultValue);
|
||||
}
|
||||
|
||||
static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata, K key, V value)
|
||||
@ -120,8 +117,11 @@ public class MapEntryLite<K, V> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> T parseField(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry,
|
||||
WireFormat.FieldType type, T value) throws IOException {
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
WireFormat.FieldType type,
|
||||
T value)
|
||||
throws IOException {
|
||||
switch (type) {
|
||||
case MESSAGE:
|
||||
MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder();
|
||||
@ -137,9 +137,9 @@ public class MapEntryLite<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the provided key and value as though they were wrapped by a {@link MapEntryLite}
|
||||
* to the output stream. This helper method avoids allocation of a {@link MapEntryLite}
|
||||
* built with a key and value and is called from generated code directly.
|
||||
* Serializes the provided key and value as though they were wrapped by a {@link MapEntryLite} to
|
||||
* the output stream. This helper method avoids allocation of a {@link MapEntryLite} built with a
|
||||
* key and value and is called from generated code directly.
|
||||
*/
|
||||
public void serializeTo(CodedOutputStream output, int fieldNumber, K key, V value)
|
||||
throws IOException {
|
||||
@ -149,9 +149,9 @@ public class MapEntryLite<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the message size for the provided key and value as though they were wrapped
|
||||
* by a {@link MapEntryLite}. This helper method avoids allocation of a {@link MapEntryLite}
|
||||
* built with a key and value and is called from generated code directly.
|
||||
* Computes the message size for the provided key and value as though they were wrapped by a
|
||||
* {@link MapEntryLite}. This helper method avoids allocation of a {@link MapEntryLite} built with
|
||||
* a key and value and is called from generated code directly.
|
||||
*/
|
||||
public int computeMessageSize(int fieldNumber, K key, V value) {
|
||||
return CodedOutputStream.computeTagSize(fieldNumber)
|
||||
@ -160,8 +160,8 @@ public class MapEntryLite<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an entry off of the input as a {@link Map.Entry}. This helper requires an allocation
|
||||
* so using {@link #parseInto} is preferred if possible.
|
||||
* Parses an entry off of the input as a {@link Map.Entry}. This helper requires an allocation so
|
||||
* using {@link #parseInto} is preferred if possible.
|
||||
*/
|
||||
public Map.Entry<K, V> parseEntry(ByteString bytes, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
@ -170,7 +170,7 @@ public class MapEntryLite<K, V> {
|
||||
|
||||
static <K, V> Map.Entry<K, V> parseEntry(
|
||||
CodedInputStream input, Metadata<K, V> metadata, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException{
|
||||
throws IOException {
|
||||
K key = metadata.defaultKey;
|
||||
V value = metadata.defaultValue;
|
||||
while (true) {
|
||||
@ -192,12 +192,12 @@ public class MapEntryLite<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an entry off of the input into the map. This helper avoids allocaton of a
|
||||
* {@link MapEntryLite} by parsing directly into the provided {@link MapFieldLite}.
|
||||
* Parses an entry off of the input into the map. This helper avoids allocaton of a {@link
|
||||
* MapEntryLite} by parsing directly into the provided {@link MapFieldLite}.
|
||||
*/
|
||||
public void parseInto(
|
||||
MapFieldLite<K, V> map, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
throws IOException {
|
||||
int length = input.readRawVarint32();
|
||||
final int oldLimit = input.pushLimit(length);
|
||||
K key = metadata.defaultKey;
|
||||
|
@ -44,38 +44,44 @@ import java.util.Set;
|
||||
/**
|
||||
* 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.
|
||||
* <p>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.
|
||||
* <p>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.
|
||||
* <p>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> implements MutabilityOracle {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <ul>
|
||||
* <li>MAP: Data is stored in mapData.
|
||||
* <li>LIST: Data is stored in listData.
|
||||
* <li>BOTH: mapData and listData have the same data.
|
||||
* </ul>
|
||||
*
|
||||
* When the map field is accessed (through generated API or reflection API),
|
||||
* it will shift between these 3 modes:
|
||||
* <p>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
|
||||
* <pre>
|
||||
* <b>getMap() getList() getMutableMap() getMutableList()</b>
|
||||
* <b>MAP</b> MAP BOTH MAP LIST
|
||||
* <b>LIST</b> BOTH LIST MAP LIST
|
||||
* <b>BOTH</b> BOTH BOTH MAP LIST
|
||||
* </pre>
|
||||
*
|
||||
* As the map field changes its mode, the list/map reference returned in a
|
||||
* previous method call may be invalidated.
|
||||
* <p>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 enum StorageMode {
|
||||
MAP,
|
||||
LIST,
|
||||
BOTH
|
||||
}
|
||||
|
||||
private volatile boolean isMutable;
|
||||
private volatile StorageMode mode;
|
||||
@ -85,6 +91,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
// 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();
|
||||
@ -92,6 +99,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
|
||||
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;
|
||||
}
|
||||
@ -117,10 +125,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
|
||||
private final Converter<K, V> converter;
|
||||
|
||||
private MapField(
|
||||
Converter<K, V> converter,
|
||||
StorageMode mode,
|
||||
Map<K, V> mapData) {
|
||||
private MapField(Converter<K, V> converter, StorageMode mode, Map<K, V> mapData) {
|
||||
this.converter = converter;
|
||||
this.isMutable = true;
|
||||
this.mode = mode;
|
||||
@ -128,26 +133,20 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
this.listData = null;
|
||||
}
|
||||
|
||||
private MapField(
|
||||
MapEntry<K, V> defaultEntry,
|
||||
StorageMode mode,
|
||||
Map<K, V> mapData) {
|
||||
private MapField(MapEntry<K, V> defaultEntry, StorageMode mode, Map<K, V> mapData) {
|
||||
this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
|
||||
}
|
||||
|
||||
|
||||
/** 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());
|
||||
public static <K, V> MapField<K, V> emptyMapField(MapEntry<K, V> defaultEntry) {
|
||||
return new MapField<K, V>(defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
|
||||
}
|
||||
|
||||
|
||||
/** 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 LinkedHashMap<K, V>());
|
||||
return new MapField<K, V>(defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
|
||||
}
|
||||
|
||||
|
||||
@ -163,9 +162,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) {
|
||||
List<Message> listData = new ArrayList<Message>();
|
||||
for (Map.Entry<K, V> entry : mapData.entrySet()) {
|
||||
listData.add(
|
||||
convertKeyAndValueToMessage(
|
||||
entry.getKey(), entry.getValue()));
|
||||
listData.add(convertKeyAndValueToMessage(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return listData;
|
||||
}
|
||||
@ -229,8 +226,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
|
||||
/** Returns a deep copy of this MapField. */
|
||||
public MapField<K, V> copy() {
|
||||
return new MapField<K, V>(
|
||||
converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
|
||||
return new MapField<K, V>(converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
|
||||
}
|
||||
|
||||
/** Gets the content of this MapField as a read-only List. */
|
||||
@ -258,25 +254,20 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
return listData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default instance of the message stored in the list view of this
|
||||
* map field.
|
||||
*/
|
||||
/** Gets the default instance of the message stored in the list view of this map field. */
|
||||
Message getMapEntryMessageDefaultInstance() {
|
||||
return converter.getMessageDefaultInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this list immutable. All subsequent modifications will throw an
|
||||
* {@link UnsupportedOperationException}.
|
||||
* Makes this list immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
isMutable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this field can be modified.
|
||||
*/
|
||||
/** Returns whether this field can be modified. */
|
||||
public boolean isMutable() {
|
||||
return isMutable;
|
||||
}
|
||||
@ -291,9 +282,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal map that checks for mutability before delegating.
|
||||
*/
|
||||
/** An internal map that checks for mutability before delegating. */
|
||||
private static class MutatabilityAwareMap<K, V> implements Map<K, V> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Map<K, V> delegate;
|
||||
@ -388,9 +377,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal collection that checks for mutability before delegating.
|
||||
*/
|
||||
/** An internal collection that checks for mutability before delegating. */
|
||||
private static class MutatabilityAwareCollection<E> implements Collection<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Collection<E> delegate;
|
||||
@ -487,9 +474,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal set that checks for mutability before delegating.
|
||||
*/
|
||||
/** An internal set that checks for mutability before delegating. */
|
||||
private static class MutatabilityAwareSet<E> implements Set<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Set<E> delegate;
|
||||
@ -586,9 +571,7 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal iterator that checks for mutability before delegating.
|
||||
*/
|
||||
/** An internal iterator that checks for mutability before delegating. */
|
||||
private static class MutatabilityAwareIterator<E> implements Iterator<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Iterator<E> delegate;
|
||||
|
@ -42,8 +42,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Internal representation of map fields in generated lite-runtime messages.
|
||||
*
|
||||
* This class is a protobuf implementation detail. Users shouldn't use this
|
||||
* class directly.
|
||||
* <p>This class is a protobuf implementation detail. Users shouldn't use this class directly.
|
||||
*/
|
||||
public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
@ -60,6 +59,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite();
|
||||
|
||||
static {
|
||||
EMPTY_MAP_FIELD.makeImmutable();
|
||||
}
|
||||
@ -78,16 +78,19 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "cast"})
|
||||
@Override public Set<Map.Entry<K, V>> entrySet() {
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet();
|
||||
}
|
||||
|
||||
@Override public void clear() {
|
||||
@Override
|
||||
public void clear() {
|
||||
ensureMutable();
|
||||
super.clear();
|
||||
}
|
||||
|
||||
@Override public V put(K key, V value) {
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
ensureMutable();
|
||||
checkNotNull(key);
|
||||
|
||||
@ -99,13 +102,15 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
return put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@Override public void putAll(Map<? extends K, ? extends V> m) {
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
ensureMutable();
|
||||
checkForNullKeysAndValues(m);
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
@Override public V remove(Object key) {
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
ensureMutable();
|
||||
return super.remove(key);
|
||||
}
|
||||
@ -125,9 +130,8 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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) {
|
||||
@ -147,9 +151,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two map fields are equal.
|
||||
*/
|
||||
/** Checks whether two map fields are equal. */
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
@ -168,15 +170,14 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}.
|
||||
* 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());
|
||||
result +=
|
||||
calculateHashCodeForObject(entry.getKey()) ^ calculateHashCodeForObject(entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -195,9 +196,9 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* 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) {
|
||||
@ -214,16 +215,14 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this field immutable. All subsequent modifications will throw an
|
||||
* {@link UnsupportedOperationException}.
|
||||
* Makes this field immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
isMutable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this field can be modified.
|
||||
*/
|
||||
/** Returns whether this field can be modified. */
|
||||
public boolean isMutable() {
|
||||
return isMutable;
|
||||
}
|
||||
|
@ -39,12 +39,11 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message objects.
|
||||
* <p>
|
||||
* See also {@link MessageLite}, which defines most of the methods that typical
|
||||
* users care about. {@link Message} adds to it methods that are not available
|
||||
* in the "lite" runtime. The biggest added features are introspection and
|
||||
* reflection -- i.e., getting descriptors for the message type and accessing
|
||||
* the field values dynamically.
|
||||
*
|
||||
* <p>See also {@link MessageLite}, which defines most of the methods that typical users care about.
|
||||
* {@link Message} adds to it methods that are not available in the "lite" runtime. The biggest
|
||||
* added features are introspection and reflection -- i.e., getting descriptors for the message type
|
||||
* and accessing the field values dynamically.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -59,11 +58,10 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
// Comparison and hashing
|
||||
|
||||
/**
|
||||
* Compares the specified object with this message for equality. Returns
|
||||
* {@code true} if the given object is a message of the same type (as
|
||||
* defined by {@code getDescriptorForType()}) and has identical values for
|
||||
* all of its fields. Subclasses must implement this; inheriting
|
||||
* {@code Object.equals()} is incorrect.
|
||||
* Compares the specified object with this message for equality. Returns {@code true} if the given
|
||||
* object is a message of the same type (as defined by {@code getDescriptorForType()}) and has
|
||||
* identical values for all of its fields. Subclasses must implement this; inheriting {@code
|
||||
* Object.equals()} is incorrect.
|
||||
*
|
||||
* @param other object to be compared for equality with this message
|
||||
* @return {@code true} if the specified object is equal to this message
|
||||
@ -72,10 +70,9 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
boolean equals(Object other);
|
||||
|
||||
/**
|
||||
* Returns the hash code value for this message. The hash code of a message
|
||||
* should mix the message's type (object identity of the descriptor) with its
|
||||
* contents (known and unknown field values). Subclasses must implement this;
|
||||
* inheriting {@code Object.hashCode()} is incorrect.
|
||||
* Returns the hash code value for this message. The hash code of a message should mix the
|
||||
* message's type (object identity of the descriptor) with its contents (known and unknown field
|
||||
* values). Subclasses must implement this; inheriting {@code Object.hashCode()} is incorrect.
|
||||
*
|
||||
* @return the hash code value for this message
|
||||
* @see Map#hashCode()
|
||||
@ -87,9 +84,8 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Converts the message to a string in protocol buffer text format. This is
|
||||
* just a trivial wrapper around {@link
|
||||
* TextFormat#printToString(MessageOrBuilder)}.
|
||||
* Converts the message to a string in protocol buffer text format. This is just a trivial wrapper
|
||||
* around {@link TextFormat#printToString(MessageOrBuilder)}.
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
@ -104,9 +100,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
@Override
|
||||
Builder toBuilder();
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message builders.
|
||||
*/
|
||||
/** Abstract interface implemented by Protocol Message builders. */
|
||||
interface Builder extends MessageLite.Builder, MessageOrBuilder {
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@ -114,23 +108,21 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
Builder clear();
|
||||
|
||||
/**
|
||||
* Merge {@code other} into the message being built. {@code other} must
|
||||
* have the exact same type as {@code this} (i.e.
|
||||
* {@code getDescriptorForType() == other.getDescriptorForType()}).
|
||||
* Merge {@code other} into the message being built. {@code other} must have the exact same type
|
||||
* as {@code this} (i.e. {@code getDescriptorForType() == other.getDescriptorForType()}).
|
||||
*
|
||||
* Merging occurs as follows. For each field:<br>
|
||||
* * For singular primitive fields, if the field is set in {@code other},
|
||||
* then {@code other}'s value overwrites the value in this message.<br>
|
||||
* * For singular message fields, if the field is set in {@code other},
|
||||
* it is merged into the corresponding sub-message of this message
|
||||
* using the same merging rules.<br>
|
||||
* * For repeated fields, the elements in {@code other} are concatenated
|
||||
* with the elements in this message.<br>
|
||||
* * For oneof groups, if the other message has one of the fields set,
|
||||
* the group of this message is cleared and replaced by the field
|
||||
* of the other message, so that the oneof constraint is preserved.
|
||||
* <p>Merging occurs as follows. For each field:<br>
|
||||
* * For singular primitive fields, if the field is set in {@code other}, then {@code other}'s
|
||||
* value overwrites the value in this message.<br>
|
||||
* * For singular message fields, if the field is set in {@code other}, it is merged into the
|
||||
* corresponding sub-message of this message using the same merging rules.<br>
|
||||
* * For repeated fields, the elements in {@code other} are concatenated with the elements in
|
||||
* this message.<br>
|
||||
* * For oneof groups, if the other message has one of the fields set, the group of this message
|
||||
* is cleared and replaced by the field of the other message, so that the oneof constraint is
|
||||
* preserved.
|
||||
*
|
||||
* This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
* <p>This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
*/
|
||||
Builder mergeFrom(Message other);
|
||||
|
||||
@ -152,101 +144,90 @@ public interface Message extends MessageLite, MessageOrBuilder {
|
||||
Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Get the message's type's descriptor.
|
||||
* See {@link Message#getDescriptorForType()}.
|
||||
*/
|
||||
/** Get the message's type's descriptor. See {@link Message#getDescriptorForType()}. */
|
||||
@Override
|
||||
Descriptors.Descriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* Create a Builder for messages of the appropriate type for the given
|
||||
* field. Messages built with this can then be passed to setField(),
|
||||
* setRepeatedField(), or addRepeatedField().
|
||||
* Create a Builder for messages of the appropriate type for the given field. Messages built
|
||||
* with this can then be passed to setField(), setRepeatedField(), or addRepeatedField().
|
||||
*/
|
||||
Builder newBuilderForField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Get a nested builder instance for the given field.
|
||||
* <p>
|
||||
* Normally, we hold a reference to the immutable message object for the
|
||||
* message type field. Some implementations(the generated message builders),
|
||||
* however, can also hold a reference to the builder object (a nested
|
||||
* builder) for the field.
|
||||
* <p>
|
||||
* If the field is already backed up by a nested builder, the nested builder
|
||||
* will be returned. Otherwise, a new field builder will be created and
|
||||
* returned. The original message field (if exist) will be merged into the
|
||||
* field builder, which will then be nested into its parent builder.
|
||||
* <p>
|
||||
* NOTE: implementations that do not support nested builders will throw
|
||||
* <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* <p>Normally, we hold a reference to the immutable message object for the message type field.
|
||||
* Some implementations(the generated message builders), however, can also hold a reference to
|
||||
* the builder object (a nested builder) for the field.
|
||||
*
|
||||
* <p>If the field is already backed up by a nested builder, the nested builder will be
|
||||
* returned. Otherwise, a new field builder will be created and returned. The original message
|
||||
* field (if exist) will be merged into the field builder, which will then be nested into its
|
||||
* parent builder.
|
||||
*
|
||||
* <p>NOTE: implementations that do not support nested builders will throw <code>
|
||||
* UnsupportedOperationException</code>.
|
||||
*/
|
||||
Builder getFieldBuilder(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Get a nested builder instance for the given repeated field instance.
|
||||
* <p>
|
||||
* Normally, we hold a reference to the immutable message object for the
|
||||
* message type field. Some implementations(the generated message builders),
|
||||
* however, can also hold a reference to the builder object (a nested
|
||||
* builder) for the field.
|
||||
* <p>
|
||||
* If the field is already backed up by a nested builder, the nested builder
|
||||
* will be returned. Otherwise, a new field builder will be created and
|
||||
* returned. The original message field (if exist) will be merged into the
|
||||
* field builder, which will then be nested into its parent builder.
|
||||
* <p>
|
||||
* NOTE: implementations that do not support nested builders will throw
|
||||
* <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* <p>Normally, we hold a reference to the immutable message object for the message type field.
|
||||
* Some implementations(the generated message builders), however, can also hold a reference to
|
||||
* the builder object (a nested builder) for the field.
|
||||
*
|
||||
* <p>If the field is already backed up by a nested builder, the nested builder will be
|
||||
* returned. Otherwise, a new field builder will be created and returned. The original message
|
||||
* field (if exist) will be merged into the field builder, which will then be nested into its
|
||||
* parent builder.
|
||||
*
|
||||
* <p>NOTE: implementations that do not support nested builders will throw <code>
|
||||
* UnsupportedOperationException</code>.
|
||||
*/
|
||||
Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field,
|
||||
int index);
|
||||
Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field, int index);
|
||||
|
||||
/**
|
||||
* Sets a field to the given value. The value must be of the correct type
|
||||
* for this field, i.e. the same type that
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} would return.
|
||||
* Sets a field to the given value. The value must be of the correct type for this field, i.e.
|
||||
* the same type that {@link Message#getField(Descriptors.FieldDescriptor)} would return.
|
||||
*/
|
||||
Builder setField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/**
|
||||
* Clears the field. This is exactly equivalent to calling the generated
|
||||
* "clear" accessor method corresponding to the field.
|
||||
* Clears the field. This is exactly equivalent to calling the generated "clear" accessor method
|
||||
* corresponding to the field.
|
||||
*/
|
||||
Builder clearField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Clears the oneof. This is exactly equivalent to calling the generated
|
||||
* "clear" accessor method corresponding to the oneof.
|
||||
* Clears the oneof. This is exactly equivalent to calling the generated "clear" accessor method
|
||||
* corresponding to the oneof.
|
||||
*/
|
||||
Builder clearOneof(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Sets an element of a repeated field to the given value. The value must
|
||||
* be of the correct type for this field, i.e. the same type that
|
||||
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
|
||||
* return.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
* Sets an element of a repeated field to the given value. The value must be of the correct type
|
||||
* for this field, i.e. the same type that {@link
|
||||
* Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would return.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Builder setRepeatedField(Descriptors.FieldDescriptor field,
|
||||
int index, Object value);
|
||||
Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
|
||||
|
||||
/**
|
||||
* Like {@code setRepeatedField}, but appends the value as a new element.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/** Set the {@link UnknownFieldSet} for this message. */
|
||||
Builder setUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
/**
|
||||
* Merge some unknown fields into the {@link UnknownFieldSet} for this
|
||||
* message.
|
||||
*/
|
||||
/** Merge some unknown fields into the {@link UnknownFieldSet} for this message. */
|
||||
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
@ -40,91 +40,79 @@ import java.io.OutputStream;
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message objects.
|
||||
*
|
||||
* <p>This interface is implemented by all protocol message objects. Non-lite
|
||||
* messages additionally implement the Message interface, which is a subclass
|
||||
* of MessageLite. Use MessageLite instead when you only need the subset of
|
||||
* features which it supports -- namely, nothing that uses descriptors or
|
||||
* reflection. You can instruct the protocol compiler to generate classes
|
||||
* which implement only MessageLite, not the full Message interface, by adding
|
||||
* the follow line to the .proto file:
|
||||
* <p>This interface is implemented by all protocol message objects. Non-lite messages additionally
|
||||
* implement the Message interface, which is a subclass of MessageLite. Use MessageLite instead when
|
||||
* you only need the subset of features which it supports -- namely, nothing that uses descriptors
|
||||
* or reflection. You can instruct the protocol compiler to generate classes which implement only
|
||||
* MessageLite, not the full Message interface, by adding the follow line to the .proto file:
|
||||
*
|
||||
* <pre>
|
||||
* option optimize_for = LITE_RUNTIME;
|
||||
* </pre>
|
||||
*
|
||||
* <p>This is particularly useful on resource-constrained systems where the
|
||||
* full protocol buffers runtime library is too big.
|
||||
* <p>This is particularly useful on resource-constrained systems where the full protocol buffers
|
||||
* runtime library is too big.
|
||||
*
|
||||
* <p>Note that on non-constrained systems (e.g. servers) when you need to link
|
||||
* in lots of protocol definitions, a better way to reduce total code footprint
|
||||
* is to use {@code optimize_for = CODE_SIZE}. This will make the generated
|
||||
* code smaller while still supporting all the same features (at the expense of
|
||||
* speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
|
||||
* small number of message types linked into your binary, in which case the
|
||||
* size of the protocol buffers runtime itself is the biggest problem.
|
||||
* <p>Note that on non-constrained systems (e.g. servers) when you need to link in lots of protocol
|
||||
* definitions, a better way to reduce total code footprint is to use {@code optimize_for =
|
||||
* CODE_SIZE}. This will make the generated code smaller while still supporting all the same
|
||||
* features (at the expense of speed). {@code optimize_for = LITE_RUNTIME} is best when you only
|
||||
* have a small number of message types linked into your binary, in which case the size of the
|
||||
* protocol buffers runtime itself is the biggest problem.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface MessageLite extends MessageLiteOrBuilder {
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This does not
|
||||
* flush or close the stream.
|
||||
* Serializes the message and writes it to {@code output}. This does not flush or close the
|
||||
* stream.
|
||||
*/
|
||||
void writeTo(CodedOutputStream output) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this message. The result
|
||||
* is only computed on the first call and memoized after that.
|
||||
* Get the number of bytes required to encode this message. The result is only computed on the
|
||||
* first call and memoized after that.
|
||||
*/
|
||||
int getSerializedSize();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the parser for a message of the same type as this message.
|
||||
*/
|
||||
/** Gets the parser for a message of the same type as this message. */
|
||||
Parser<? extends MessageLite> getParserForType();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}.
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is just a trivial wrapper
|
||||
* around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
ByteString toByteString();
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code byte} array and returns it. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}.
|
||||
* Serializes the message to a {@code byte} array and returns it. This is just a trivial wrapper
|
||||
* around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
byte[] toByteArray();
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This is just a
|
||||
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
|
||||
* not flush or close the stream.
|
||||
* <p>
|
||||
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
|
||||
* any more data to the stream after the message, you must somehow ensure
|
||||
* that the parser on the receiving end does not interpret this as being
|
||||
* part of the protocol message. This can be done e.g. by writing the size
|
||||
* of the message before the data, then making sure to limit the input to
|
||||
* that size on the receiving end (e.g. by wrapping the InputStream in one
|
||||
* which limits the input). Alternatively, just use
|
||||
* {@link #writeDelimitedTo(OutputStream)}.
|
||||
* Serializes the message and writes it to {@code output}. This is just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}. This does not flush or close the stream.
|
||||
*
|
||||
* <p>NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write any more data to the
|
||||
* stream after the message, you must somehow ensure that the parser on the receiving end does not
|
||||
* interpret this as being part of the protocol message. This can be done e.g. by writing the size
|
||||
* of the message before the data, then making sure to limit the input to that size on the
|
||||
* receiving end (e.g. by wrapping the InputStream in one which limits the input). Alternatively,
|
||||
* just use {@link #writeDelimitedTo(OutputStream)}.
|
||||
*/
|
||||
void writeTo(OutputStream output) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
|
||||
* as a varint before writing the data. This allows more data to be written
|
||||
* to the stream after the message without the need to delimit the message
|
||||
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
|
||||
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
|
||||
* to parse messages written by this method.
|
||||
* Like {@link #writeTo(OutputStream)}, but writes the size of the message as a varint before
|
||||
* writing the data. This allows more data to be written to the stream after the message without
|
||||
* the need to delimit the message data yourself. Use {@link
|
||||
* Builder#mergeDelimitedFrom(InputStream)} (or the static method {@code
|
||||
* YourMessageType.parseDelimitedFrom(InputStream)}) to parse messages written by this method.
|
||||
*/
|
||||
void writeDelimitedTo(OutputStream output) throws IOException;
|
||||
|
||||
@ -132,210 +120,179 @@ public interface MessageLite extends MessageLiteOrBuilder {
|
||||
// =================================================================
|
||||
// Builders
|
||||
|
||||
/**
|
||||
* Constructs a new builder for a message of the same type as this message.
|
||||
*/
|
||||
/** Constructs a new builder for a message of the same type as this message. */
|
||||
Builder newBuilderForType();
|
||||
|
||||
/**
|
||||
* Constructs a builder initialized with the current message. Use this to
|
||||
* derive a new message from the current one.
|
||||
* Constructs a builder initialized with the current message. Use this to derive a new message
|
||||
* from the current one.
|
||||
*/
|
||||
Builder toBuilder();
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message builders.
|
||||
*/
|
||||
/** Abstract interface implemented by Protocol Message builders. */
|
||||
interface Builder extends MessageLiteOrBuilder, Cloneable {
|
||||
/** Resets all fields to their default values. */
|
||||
Builder clear();
|
||||
|
||||
/**
|
||||
* Constructs the message based on the state of the Builder. Subsequent
|
||||
* changes to the Builder will not affect the returned message.
|
||||
* @throws UninitializedMessageException The message is missing one or more
|
||||
* required fields (i.e. {@link #isInitialized()} returns false).
|
||||
* Use {@link #buildPartial()} to bypass this check.
|
||||
* Constructs the message based on the state of the Builder. Subsequent changes to the Builder
|
||||
* will not affect the returned message.
|
||||
*
|
||||
* @throws UninitializedMessageException The message is missing one or more required fields
|
||||
* (i.e. {@link #isInitialized()} returns false). Use {@link #buildPartial()} to bypass this
|
||||
* check.
|
||||
*/
|
||||
MessageLite build();
|
||||
|
||||
/**
|
||||
* Like {@link #build()}, but does not throw an exception if the message
|
||||
* is missing required fields. Instead, a partial message is returned.
|
||||
* Subsequent changes to the Builder will not affect the returned message.
|
||||
* Like {@link #build()}, but does not throw an exception if the message is missing required
|
||||
* fields. Instead, a partial message is returned. Subsequent changes to the Builder will not
|
||||
* affect the returned message.
|
||||
*/
|
||||
MessageLite buildPartial();
|
||||
|
||||
/**
|
||||
* Clones the Builder.
|
||||
*
|
||||
* @see Object#clone()
|
||||
*/
|
||||
Builder clone();
|
||||
|
||||
/**
|
||||
* Parses a message of this type from the input and merges it with this
|
||||
* message.
|
||||
* Parses a message of this type from the input and merges it with this message.
|
||||
*
|
||||
* <p>Warning: This does not verify that all required fields are present in the input message.
|
||||
* If you call {@link #build()} without setting all required fields, it will throw an {@link
|
||||
* UninitializedMessageException}, which is a {@code RuntimeException} and thus might not be
|
||||
* caught. There are a few good ways to deal with this:
|
||||
*
|
||||
* <p>Warning: This does not verify that all required fields are present in
|
||||
* the input message. If you call {@link #build()} without setting all
|
||||
* required fields, it will throw an {@link UninitializedMessageException},
|
||||
* which is a {@code RuntimeException} and thus might not be caught. There
|
||||
* are a few good ways to deal with this:
|
||||
* <ul>
|
||||
* <li>Call {@link #isInitialized()} to verify that all required fields
|
||||
* are set before building.
|
||||
* <li>Use {@code buildPartial()} to build, which ignores missing
|
||||
* required fields.
|
||||
* <li>Call {@link #isInitialized()} to verify that all required fields are set before
|
||||
* building.
|
||||
* <li>Use {@code buildPartial()} to build, which ignores missing required fields.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: The caller should call
|
||||
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
|
||||
* verify that the last tag seen was the appropriate end-group tag,
|
||||
* or zero for EOF.
|
||||
* <p>Note: The caller should call {@link CodedInputStream#checkLastTagWas(int)} after calling
|
||||
* this to verify that the last tag seen was the appropriate end-group tag, or zero for EOF.
|
||||
*/
|
||||
Builder mergeFrom(CodedInputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
|
||||
* parses extensions. The extensions that you want to be able to parse
|
||||
* must be registered in {@code extensionRegistry}. Extensions not in
|
||||
* the registry will be treated as unknown fields.
|
||||
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also parses extensions. The extensions
|
||||
* that you want to be able to parse must be registered in {@code extensionRegistry}. Extensions
|
||||
* not in the registry will be treated as unknown fields.
|
||||
*/
|
||||
Builder mergeFrom(CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException;
|
||||
Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
* Parse {@code data} as a message of this type and merge it with the message being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse a message of this type from {@code input} and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
|
||||
* reads the <i>entire</i> input (unless it throws an exception). If you
|
||||
* want it to stop earlier, you will need to wrap your input in some
|
||||
* wrapper stream that limits reading. Or, use
|
||||
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
|
||||
* and {@link #mergeDelimitedFrom(InputStream)} to read it.
|
||||
* <p>
|
||||
* Despite usually reading the entire input, this does not close the stream.
|
||||
* Parse a message of this type from {@code input} and merge it with the message being built.
|
||||
* This is just a small wrapper around {@link #mergeFrom(CodedInputStream)}. Note that this
|
||||
* method always reads the <i>entire</i> input (unless it throws an exception). If you want it
|
||||
* to stop earlier, you will need to wrap your input in some wrapper stream that limits reading.
|
||||
* Or, use {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message and {@link
|
||||
* #mergeDelimitedFrom(InputStream)} to read it.
|
||||
*
|
||||
* <p>Despite usually reading the entire input, this does not close the stream.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(InputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Parse a message of this type from {@code input} and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
* Parse a message of this type from {@code input} and merge it with the message being built.
|
||||
* This is just a small wrapper around {@link
|
||||
* #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
Builder mergeFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Merge {@code other} into the message being built. {@code other} must
|
||||
* have the exact same type as {@code this} (i.e.
|
||||
* {@code getClass().equals(getDefaultInstanceForType().getClass())}).
|
||||
* Merge {@code other} into the message being built. {@code other} must have the exact same type
|
||||
* as {@code this} (i.e. {@code getClass().equals(getDefaultInstanceForType().getClass())}).
|
||||
*
|
||||
* Merging occurs as follows. For each field:<br>
|
||||
* * For singular primitive fields, if the field is set in {@code other},
|
||||
* then {@code other}'s value overwrites the value in this message.<br>
|
||||
* * For singular message fields, if the field is set in {@code other},
|
||||
* it is merged into the corresponding sub-message of this message
|
||||
* using the same merging rules.<br>
|
||||
* * For repeated fields, the elements in {@code other} are concatenated
|
||||
* with the elements in this message.
|
||||
* * For oneof groups, if the other message has one of the fields set,
|
||||
* the group of this message is cleared and replaced by the field
|
||||
* of the other message, so that the oneof constraint is preserved.
|
||||
* <p>Merging occurs as follows. For each field:<br>
|
||||
* * For singular primitive fields, if the field is set in {@code other}, then {@code other}'s
|
||||
* value overwrites the value in this message.<br>
|
||||
* * For singular message fields, if the field is set in {@code other}, it is merged into the
|
||||
* corresponding sub-message of this message using the same merging rules.<br>
|
||||
* * For repeated fields, the elements in {@code other} are concatenated with the elements in
|
||||
* this message. * For oneof groups, if the other message has one of the fields set, the group
|
||||
* of this message is cleared and replaced by the field of the other message, so that the oneof
|
||||
* constraint is preserved.
|
||||
*
|
||||
* This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
* <p>This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
*/
|
||||
Builder mergeFrom(MessageLite other);
|
||||
|
||||
/**
|
||||
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
|
||||
* Instead, the size of the message (encoded as a varint) is read first,
|
||||
* then the message data. Use
|
||||
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
|
||||
* this format.
|
||||
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF. Instead, the size of the
|
||||
* message (encoded as a varint) is read first, then the message data. Use {@link
|
||||
* MessageLite#writeDelimitedTo(OutputStream)} to write messages in this format.
|
||||
*
|
||||
* @return True if successful, or false if the stream is at EOF when the
|
||||
* method starts. Any other error (including reaching EOF during
|
||||
* parsing) will cause an exception to be thrown.
|
||||
* @return True if successful, or false if the stream is at EOF when the method starts. Any
|
||||
* other error (including reaching EOF during parsing) will cause an exception to be thrown.
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input)
|
||||
throws IOException;
|
||||
boolean mergeDelimitedFrom(InputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
/** Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions. */
|
||||
boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
||||
|
@ -31,30 +31,27 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Base interface for methods common to {@link MessageLite}
|
||||
* and {@link MessageLite.Builder} to provide type equivalency.
|
||||
* Base interface for methods common to {@link MessageLite} and {@link MessageLite.Builder} to
|
||||
* provide type equivalency.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public interface MessageLiteOrBuilder {
|
||||
/**
|
||||
* Get an instance of the type with no fields set. Because no fields are set,
|
||||
* all getters for singular fields will return default values and repeated
|
||||
* fields will appear empty.
|
||||
* This may or may not be a singleton. This differs from the
|
||||
* {@code getDefaultInstance()} method of generated message classes in that
|
||||
* this method is an abstract method of the {@code MessageLite} interface
|
||||
* whereas {@code getDefaultInstance()} is a static method of a specific
|
||||
* class. They return the same thing.
|
||||
* Get an instance of the type with no fields set. Because no fields are set, all getters for
|
||||
* singular fields will return default values and repeated fields will appear empty. This may or
|
||||
* may not be a singleton. This differs from the {@code getDefaultInstance()} method of generated
|
||||
* message classes in that this method is an abstract method of the {@code MessageLite} interface
|
||||
* whereas {@code getDefaultInstance()} is a static method of a specific class. They return the
|
||||
* same thing.
|
||||
*/
|
||||
MessageLite getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Returns true if all required fields in the message and all embedded
|
||||
* messages are set, false otherwise.
|
||||
* Returns true if all required fields in the message and all embedded messages are set, false
|
||||
* otherwise.
|
||||
*
|
||||
* <p>See also: {@link MessageOrBuilder#getInitializationErrorString()}
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base interface for methods common to {@link Message} and
|
||||
* {@link Message.Builder} to provide type equivalency.
|
||||
* Base interface for methods common to {@link Message} and {@link Message.Builder} to provide type
|
||||
* equivalency.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@ -46,95 +46,85 @@ public interface MessageOrBuilder extends MessageLiteOrBuilder {
|
||||
Message getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Returns a list of field paths (e.g. "foo.bar.baz") of required fields
|
||||
* which are not set in this message. You should call
|
||||
* {@link MessageLiteOrBuilder#isInitialized()} first to check if there
|
||||
* are any missing fields, as that method is likely to be much faster
|
||||
* than this one even when the message is fully-initialized.
|
||||
* Returns a list of field paths (e.g. "foo.bar.baz") of required fields which are not set in this
|
||||
* message. You should call {@link MessageLiteOrBuilder#isInitialized()} first to check if there
|
||||
* are any missing fields, as that method is likely to be much faster than this one even when the
|
||||
* message is fully-initialized.
|
||||
*/
|
||||
List<String> findInitializationErrors();
|
||||
|
||||
/**
|
||||
* Returns a comma-delimited list of required fields which are not set
|
||||
* in this message object. You should call
|
||||
* {@link MessageLiteOrBuilder#isInitialized()} first to check if there
|
||||
* are any missing fields, as that method is likely to be much faster
|
||||
* than this one even when the message is fully-initialized.
|
||||
* Returns a comma-delimited list of required fields which are not set in this message object. You
|
||||
* should call {@link MessageLiteOrBuilder#isInitialized()} first to check if there are any
|
||||
* missing fields, as that method is likely to be much faster than this one even when the message
|
||||
* is fully-initialized.
|
||||
*/
|
||||
String getInitializationErrorString();
|
||||
|
||||
/**
|
||||
* Get the message's type's descriptor. This differs from the
|
||||
* {@code getDescriptor()} method of generated message classes in that
|
||||
* this method is an abstract method of the {@code Message} interface
|
||||
* whereas {@code getDescriptor()} is a static method of a specific class.
|
||||
* They return the same thing.
|
||||
* Get the message's type's descriptor. This differs from the {@code getDescriptor()} method of
|
||||
* generated message classes in that this method is an abstract method of the {@code Message}
|
||||
* interface whereas {@code getDescriptor()} is a static method of a specific class. They return
|
||||
* the same thing.
|
||||
*/
|
||||
Descriptors.Descriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* Returns a collection of all the fields in this message which are set
|
||||
* and their corresponding values. A singular ("required" or "optional")
|
||||
* field is set iff hasField() returns true for that field. A "repeated"
|
||||
* field is set iff getRepeatedFieldCount() is greater than zero. The
|
||||
* values are exactly what would be returned by calling
|
||||
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
|
||||
* is guaranteed to be a sorted map, so iterating over it will return fields
|
||||
* in order by field number.
|
||||
* <br>
|
||||
* If this is for a builder, the returned map may or may not reflect future
|
||||
* changes to the builder. Either way, the returned map is itself
|
||||
* unmodifiable.
|
||||
* Returns a collection of all the fields in this message which are set and their corresponding
|
||||
* values. A singular ("required" or "optional") field is set iff hasField() returns true for that
|
||||
* field. A "repeated" field is set iff getRepeatedFieldCount() is greater than zero. The values
|
||||
* are exactly what would be returned by calling {@link #getField(Descriptors.FieldDescriptor)}
|
||||
* for each field. The map is guaranteed to be a sorted map, so iterating over it will return
|
||||
* fields in order by field number. <br>
|
||||
* If this is for a builder, the returned map may or may not reflect future changes to the
|
||||
* builder. Either way, the returned map is itself unmodifiable.
|
||||
*/
|
||||
Map<Descriptors.FieldDescriptor, Object> getAllFields();
|
||||
|
||||
/**
|
||||
* Returns true if the given oneof is set.
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code oneof.getContainingType() != getDescriptorForType()}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code oneof.getContainingType() !=
|
||||
* getDescriptorForType()}.
|
||||
*/
|
||||
boolean hasOneof(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Obtains the FieldDescriptor if the given oneof is set. Returns null
|
||||
* if no field is set.
|
||||
*/
|
||||
Descriptors.FieldDescriptor getOneofFieldDescriptor(
|
||||
Descriptors.OneofDescriptor oneof);
|
||||
/** Obtains the FieldDescriptor if the given oneof is set. Returns null if no field is set. */
|
||||
Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Returns true if the given field is set. This is exactly equivalent to
|
||||
* calling the generated "has" accessor method corresponding to the field.
|
||||
* @throws IllegalArgumentException The field is a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
* Returns true if the given field is set. This is exactly equivalent to calling the generated
|
||||
* "has" accessor method corresponding to the field.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
boolean hasField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Obtains the value of the given field, or the default value if it is
|
||||
* not set. For primitive fields, the boxed primitive value is returned.
|
||||
* For enum fields, the EnumValueDescriptor for the value is returned. For
|
||||
* embedded message fields, the sub-message is returned. For repeated
|
||||
* Obtains the value of the given field, or the default value if it is not set. For primitive
|
||||
* fields, the boxed primitive value is returned. For enum fields, the EnumValueDescriptor for the
|
||||
* value is returned. For embedded message fields, the sub-message is returned. For repeated
|
||||
* fields, a java.util.List is returned.
|
||||
*/
|
||||
Object getField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Gets the number of elements of a repeated field. This is exactly
|
||||
* equivalent to calling the generated "Count" accessor method corresponding
|
||||
* to the field.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
* Gets the number of elements of a repeated field. This is exactly equivalent to calling the
|
||||
* generated "Count" accessor method corresponding to the field.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Gets an element of a repeated field. For primitive fields, the boxed
|
||||
* primitive value is returned. For enum fields, the EnumValueDescriptor
|
||||
* for the value is returned. For embedded message fields, the sub-message
|
||||
* is returned.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
* Gets an element of a repeated field. For primitive fields, the boxed primitive value is
|
||||
* returned. For enum fields, the EnumValueDescriptor for the value is returned. For embedded
|
||||
* message fields, the sub-message is returned.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
|
||||
|
||||
|
@ -54,20 +54,19 @@ class MessageReflection {
|
||||
message.getDescriptorForType().getOptions().getMessageSetWireFormat();
|
||||
if (alwaysWriteRequiredFields) {
|
||||
fields = new TreeMap<FieldDescriptor, Object>(fields);
|
||||
for (final FieldDescriptor field :
|
||||
message.getDescriptorForType().getFields()) {
|
||||
for (final FieldDescriptor field : message.getDescriptorForType().getFields()) {
|
||||
if (field.isRequired() && !fields.containsKey(field)) {
|
||||
fields.put(field, message.getField(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
|
||||
fields.entrySet()) {
|
||||
for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : fields.entrySet()) {
|
||||
final Descriptors.FieldDescriptor field = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
if (isMessageSet && field.isExtension() &&
|
||||
field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
|
||||
!field.isRepeated()) {
|
||||
if (isMessageSet
|
||||
&& field.isExtension()
|
||||
&& field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE
|
||||
&& !field.isRepeated()) {
|
||||
output.writeMessageSetExtension(field.getNumber(), (Message) value);
|
||||
} else {
|
||||
FieldSet.writeField(field, value, output);
|
||||
@ -82,22 +81,20 @@ class MessageReflection {
|
||||
}
|
||||
}
|
||||
|
||||
static int getSerializedSize(
|
||||
Message message,
|
||||
Map<FieldDescriptor, Object> fields) {
|
||||
static int getSerializedSize(Message message, Map<FieldDescriptor, Object> fields) {
|
||||
int size = 0;
|
||||
final boolean isMessageSet =
|
||||
message.getDescriptorForType().getOptions().getMessageSetWireFormat();
|
||||
|
||||
for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
|
||||
fields.entrySet()) {
|
||||
for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry : fields.entrySet()) {
|
||||
final Descriptors.FieldDescriptor field = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
if (isMessageSet && field.isExtension() &&
|
||||
field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
|
||||
!field.isRepeated()) {
|
||||
size += CodedOutputStream.computeMessageSetExtensionSize(
|
||||
field.getNumber(), (Message) value);
|
||||
if (isMessageSet
|
||||
&& field.isExtension()
|
||||
&& field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE
|
||||
&& !field.isRepeated()) {
|
||||
size +=
|
||||
CodedOutputStream.computeMessageSetExtensionSize(field.getNumber(), (Message) value);
|
||||
} else {
|
||||
size += FieldSet.computeFieldSize(field, value);
|
||||
}
|
||||
@ -126,9 +123,7 @@ class MessageReflection {
|
||||
@SuppressWarnings("unchecked")
|
||||
static boolean isInitialized(MessageOrBuilder message) {
|
||||
// Check that all required fields are present.
|
||||
for (final Descriptors.FieldDescriptor field : message
|
||||
.getDescriptorForType()
|
||||
.getFields()) {
|
||||
for (final Descriptors.FieldDescriptor field : message.getDescriptorForType().getFields()) {
|
||||
if (field.isRequired()) {
|
||||
if (!message.hasField(field)) {
|
||||
return false;
|
||||
@ -142,8 +137,7 @@ class MessageReflection {
|
||||
final Descriptors.FieldDescriptor field = entry.getKey();
|
||||
if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (field.isRepeated()) {
|
||||
for (final Message element
|
||||
: (List<Message>) entry.getValue()) {
|
||||
for (final Message element : (List<Message>) entry.getValue()) {
|
||||
if (!element.isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
@ -159,31 +153,24 @@ class MessageReflection {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String subMessagePrefix(final String prefix,
|
||||
final Descriptors.FieldDescriptor field,
|
||||
final int index) {
|
||||
private static String subMessagePrefix(
|
||||
final String prefix, final Descriptors.FieldDescriptor field, final int index) {
|
||||
final StringBuilder result = new StringBuilder(prefix);
|
||||
if (field.isExtension()) {
|
||||
result.append('(')
|
||||
.append(field.getFullName())
|
||||
.append(')');
|
||||
result.append('(').append(field.getFullName()).append(')');
|
||||
} else {
|
||||
result.append(field.getName());
|
||||
}
|
||||
if (index != -1) {
|
||||
result.append('[')
|
||||
.append(index)
|
||||
.append(']');
|
||||
result.append('[').append(index).append(']');
|
||||
}
|
||||
result.append('.');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static void findMissingFields(final MessageOrBuilder message,
|
||||
final String prefix,
|
||||
final List<String> results) {
|
||||
for (final Descriptors.FieldDescriptor field :
|
||||
message.getDescriptorForType().getFields()) {
|
||||
private static void findMissingFields(
|
||||
final MessageOrBuilder message, final String prefix, final List<String> results) {
|
||||
for (final Descriptors.FieldDescriptor field : message.getDescriptorForType().getFields()) {
|
||||
if (field.isRequired() && !message.hasField(field)) {
|
||||
results.add(prefix + field.getName());
|
||||
}
|
||||
@ -198,15 +185,13 @@ class MessageReflection {
|
||||
if (field.isRepeated()) {
|
||||
int i = 0;
|
||||
for (final Object element : (List) value) {
|
||||
findMissingFields((MessageOrBuilder) element,
|
||||
subMessagePrefix(prefix, field, i++),
|
||||
results);
|
||||
findMissingFields(
|
||||
(MessageOrBuilder) element, subMessagePrefix(prefix, field, i++), results);
|
||||
}
|
||||
} else {
|
||||
if (message.hasField(field)) {
|
||||
findMissingFields((MessageOrBuilder) value,
|
||||
subMessagePrefix(prefix, field, -1),
|
||||
results);
|
||||
findMissingFields(
|
||||
(MessageOrBuilder) value, subMessagePrefix(prefix, field, -1), results);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,11 +199,10 @@ class MessageReflection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates {@code this.missingFields} with the full "path" of each missing
|
||||
* required field in the given message.
|
||||
* Populates {@code this.missingFields} with the full "path" of each missing required field in the
|
||||
* given message.
|
||||
*/
|
||||
static List<String> findMissingFields(
|
||||
final MessageOrBuilder message) {
|
||||
static List<String> findMissingFields(final MessageOrBuilder message) {
|
||||
final List<String> results = new ArrayList<String>();
|
||||
findMissingFields(message, "", results);
|
||||
return results;
|
||||
@ -226,12 +210,11 @@ class MessageReflection {
|
||||
|
||||
static interface MergeTarget {
|
||||
enum ContainerType {
|
||||
MESSAGE, EXTENSION_SET
|
||||
MESSAGE,
|
||||
EXTENSION_SET
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor for the target.
|
||||
*/
|
||||
/** Returns the descriptor for the target. */
|
||||
public Descriptors.Descriptor getDescriptorForType();
|
||||
|
||||
public ContainerType getContainerType();
|
||||
@ -240,21 +223,19 @@ class MessageReflection {
|
||||
ExtensionRegistry registry, String name);
|
||||
|
||||
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
|
||||
ExtensionRegistry registry, Descriptors.Descriptor containingType,
|
||||
int fieldNumber);
|
||||
ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber);
|
||||
|
||||
/**
|
||||
* Obtains the value of the given field, or the default value if it is not
|
||||
* set. For primitive fields, the boxed primitive value is returned. For
|
||||
* enum fields, the EnumValueDescriptor for the value is returned. For
|
||||
* embedded message fields, the sub-message is returned. For repeated
|
||||
* Obtains the value of the given field, or the default value if it is not set. For primitive
|
||||
* fields, the boxed primitive value is returned. For enum fields, the EnumValueDescriptor for
|
||||
* the value is returned. For embedded message fields, the sub-message is returned. For repeated
|
||||
* fields, a java.util.List is returned.
|
||||
*/
|
||||
public Object getField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Returns true if the given field is set. This is exactly equivalent to
|
||||
* calling the generated "has" accessor method corresponding to the field.
|
||||
* Returns true if the given field is set. This is exactly equivalent to calling the generated
|
||||
* "has" accessor method corresponding to the field.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
@ -262,106 +243,98 @@ class MessageReflection {
|
||||
boolean hasField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Sets a field to the given value. The value must be of the correct type
|
||||
* for this field, i.e. the same type that
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)}
|
||||
* would return.
|
||||
* Sets a field to the given value. The value must be of the correct type for this field, i.e.
|
||||
* the same type that {@link Message#getField(Descriptors.FieldDescriptor)} would return.
|
||||
*/
|
||||
MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/**
|
||||
* Clears the field. This is exactly equivalent to calling the generated
|
||||
* "clear" accessor method corresponding to the field.
|
||||
* Clears the field. This is exactly equivalent to calling the generated "clear" accessor method
|
||||
* corresponding to the field.
|
||||
*/
|
||||
MergeTarget clearField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Sets an element of a repeated field to the given value. The value must
|
||||
* be of the correct type for this field, i.e. the same type that {@link
|
||||
* Sets an element of a repeated field to the given value. The value must be of the correct type
|
||||
* for this field, i.e. the same type that {@link
|
||||
* Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() !=
|
||||
* getDescriptorForType()}.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
|
||||
int index, Object value);
|
||||
MergeTarget setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
|
||||
|
||||
/**
|
||||
* Like {@code setRepeatedField}, but appends the value as a new element.
|
||||
*
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() !=
|
||||
* getDescriptorForType()}.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
|
||||
Object value);
|
||||
MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/**
|
||||
* Returns true if the given oneof is set.
|
||||
*
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code oneof.getContainingType() != getDescriptorForType()}.
|
||||
* @throws IllegalArgumentException if {@code oneof.getContainingType() !=
|
||||
* getDescriptorForType()}.
|
||||
*/
|
||||
boolean hasOneof(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Clears the oneof. This is exactly equivalent to calling the generated
|
||||
* "clear" accessor method corresponding to the oneof.
|
||||
* Clears the oneof. This is exactly equivalent to calling the generated "clear" accessor method
|
||||
* corresponding to the oneof.
|
||||
*/
|
||||
MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Obtains the FieldDescriptor if the given oneof is set. Returns null
|
||||
* if no field is set.
|
||||
*/
|
||||
/** Obtains the FieldDescriptor if the given oneof is set. Returns null if no field is set. */
|
||||
Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
|
||||
|
||||
/**
|
||||
* Parse the input stream into a sub field group defined based on either
|
||||
* FieldDescriptor or the default instance.
|
||||
* Parse the input stream into a sub field group defined based on either FieldDescriptor or the
|
||||
* default instance.
|
||||
*/
|
||||
Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
|
||||
Object parseGroup(
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor,
|
||||
Message defaultInstance)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Parse the input stream into a sub field message defined based on either
|
||||
* FieldDescriptor or the default instance.
|
||||
* Parse the input stream into a sub field message defined based on either FieldDescriptor or
|
||||
* the default instance.
|
||||
*/
|
||||
Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
|
||||
Object parseMessage(
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor,
|
||||
Message defaultInstance)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Parse from a ByteString into a sub field message defined based on either
|
||||
* FieldDescriptor or the default instance. There isn't a varint indicating
|
||||
* the length of the message at the beginning of the input ByteString.
|
||||
* Parse from a ByteString into a sub field message defined based on either FieldDescriptor or
|
||||
* the default instance. There isn't a varint indicating the length of the message at the
|
||||
* beginning of the input ByteString.
|
||||
*/
|
||||
Object parseMessageFromBytes(
|
||||
ByteString bytes, ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor, Message defaultInstance)
|
||||
ByteString bytes,
|
||||
ExtensionRegistryLite registry,
|
||||
Descriptors.FieldDescriptor descriptor,
|
||||
Message defaultInstance)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the UTF8 validation level for the field.
|
||||
*/
|
||||
WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor
|
||||
descriptor);
|
||||
/** Returns the UTF8 validation level for the field. */
|
||||
WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor);
|
||||
|
||||
/**
|
||||
* Returns a new merge target for a sub-field. When defaultInstance is
|
||||
* provided, it indicates the descriptor is for an extension type, and
|
||||
* implementations should create a new instance from the defaultInstance
|
||||
* prototype directly.
|
||||
* Returns a new merge target for a sub-field. When defaultInstance is provided, it indicates
|
||||
* the descriptor is for an extension type, and implementations should create a new instance
|
||||
* from the defaultInstance prototype directly.
|
||||
*/
|
||||
MergeTarget newMergeTargetForField(
|
||||
Descriptors.FieldDescriptor descriptor,
|
||||
Message defaultInstance);
|
||||
Descriptors.FieldDescriptor descriptor, Message defaultInstance);
|
||||
|
||||
/**
|
||||
* Finishes the merge and returns the underlying object.
|
||||
*/
|
||||
/** Finishes the merge and returns the underlying object. */
|
||||
Object finish();
|
||||
}
|
||||
|
||||
@ -443,8 +416,7 @@ class MessageReflection {
|
||||
@Override
|
||||
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
|
||||
ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
|
||||
return registry.findImmutableExtensionByNumber(containingType,
|
||||
fieldNumber);
|
||||
return registry.findImmutableExtensionByNumber(containingType, fieldNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -523,8 +495,7 @@ class MessageReflection {
|
||||
public MergeTarget newMergeTargetForField(
|
||||
Descriptors.FieldDescriptor field, Message defaultInstance) {
|
||||
if (defaultInstance != null) {
|
||||
return new BuilderAdapter(
|
||||
defaultInstance.newBuilderForType());
|
||||
return new BuilderAdapter(defaultInstance.newBuilderForType());
|
||||
} else {
|
||||
return new BuilderAdapter(builder.newBuilderForField(field));
|
||||
}
|
||||
@ -536,8 +507,7 @@ class MessageReflection {
|
||||
return WireFormat.Utf8Validation.STRICT;
|
||||
}
|
||||
// TODO(liujisi): support lazy strings for repeated fields.
|
||||
if (!descriptor.isRepeated()
|
||||
&& builder instanceof GeneratedMessage.Builder) {
|
||||
if (!descriptor.isRepeated() && builder instanceof GeneratedMessage.Builder) {
|
||||
return WireFormat.Utf8Validation.LAZY;
|
||||
}
|
||||
return WireFormat.Utf8Validation.LOOSE;
|
||||
@ -560,8 +530,7 @@ class MessageReflection {
|
||||
|
||||
@Override
|
||||
public Descriptors.Descriptor getDescriptorForType() {
|
||||
throw new UnsupportedOperationException(
|
||||
"getDescriptorForType() called on FieldSet object");
|
||||
throw new UnsupportedOperationException("getDescriptorForType() called on FieldSet object");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -629,8 +598,7 @@ class MessageReflection {
|
||||
@Override
|
||||
public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
|
||||
ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
|
||||
return registry.findImmutableExtensionByNumber(containingType,
|
||||
fieldNumber);
|
||||
return registry.findImmutableExtensionByNumber(containingType, fieldNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -640,8 +608,7 @@ class MessageReflection {
|
||||
Descriptors.FieldDescriptor field,
|
||||
Message defaultInstance)
|
||||
throws IOException {
|
||||
Message.Builder subBuilder =
|
||||
defaultInstance.newBuilderForType();
|
||||
Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
||||
if (!field.isRepeated()) {
|
||||
Message originalMessage = (Message) getField(field);
|
||||
if (originalMessage != null) {
|
||||
@ -659,8 +626,7 @@ class MessageReflection {
|
||||
Descriptors.FieldDescriptor field,
|
||||
Message defaultInstance)
|
||||
throws IOException {
|
||||
Message.Builder subBuilder =
|
||||
defaultInstance.newBuilderForType();
|
||||
Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
||||
if (!field.isRepeated()) {
|
||||
Message originalMessage = (Message) getField(field);
|
||||
if (originalMessage != null) {
|
||||
@ -678,7 +644,7 @@ class MessageReflection {
|
||||
Descriptors.FieldDescriptor field,
|
||||
Message defaultInstance)
|
||||
throws IOException {
|
||||
Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
||||
Message.Builder subBuilder = defaultInstance.newBuilderForType();
|
||||
if (!field.isRepeated()) {
|
||||
Message originalMessage = (Message) getField(field);
|
||||
if (originalMessage != null) {
|
||||
@ -692,8 +658,7 @@ class MessageReflection {
|
||||
@Override
|
||||
public MergeTarget newMergeTargetForField(
|
||||
Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
|
||||
throw new UnsupportedOperationException(
|
||||
"newMergeTargetForField() called on FieldSet object");
|
||||
throw new UnsupportedOperationException("newMergeTargetForField() called on FieldSet object");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -707,8 +672,7 @@ class MessageReflection {
|
||||
|
||||
@Override
|
||||
public Object finish() {
|
||||
throw new UnsupportedOperationException(
|
||||
"finish() called on FieldSet object");
|
||||
throw new UnsupportedOperationException("finish() called on FieldSet object");
|
||||
}
|
||||
}
|
||||
|
||||
@ -731,8 +695,7 @@ class MessageReflection {
|
||||
MergeTarget target,
|
||||
int tag)
|
||||
throws IOException {
|
||||
if (type.getOptions().getMessageSetWireFormat() &&
|
||||
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
|
||||
if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
|
||||
mergeMessageSetExtensionFromCodedStream(
|
||||
input, unknownFields, extensionRegistry, type, target);
|
||||
return true;
|
||||
@ -752,19 +715,16 @@ class MessageReflection {
|
||||
// were empty.
|
||||
if (extensionRegistry instanceof ExtensionRegistry) {
|
||||
final ExtensionRegistry.ExtensionInfo extension =
|
||||
target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
|
||||
type, fieldNumber);
|
||||
target.findExtensionByNumber((ExtensionRegistry) extensionRegistry, type, fieldNumber);
|
||||
if (extension == null) {
|
||||
field = null;
|
||||
} else {
|
||||
field = extension.descriptor;
|
||||
defaultInstance = extension.defaultInstance;
|
||||
if (defaultInstance == null &&
|
||||
field.getJavaType()
|
||||
== Descriptors.FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (defaultInstance == null
|
||||
&& field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalStateException(
|
||||
"Message-typed extension lacked default instance: " +
|
||||
field.getFullName());
|
||||
"Message-typed extension lacked default instance: " + field.getFullName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -779,21 +739,19 @@ class MessageReflection {
|
||||
boolean unknown = false;
|
||||
boolean packed = false;
|
||||
if (field == null) {
|
||||
unknown = true; // Unknown field.
|
||||
} else if (wireType == FieldSet.getWireFormatForFieldType(
|
||||
field.getLiteType(),
|
||||
false /* isPacked */)) {
|
||||
unknown = true; // Unknown field.
|
||||
} else if (wireType
|
||||
== FieldSet.getWireFormatForFieldType(field.getLiteType(), /* isPacked= */ false)) {
|
||||
packed = false;
|
||||
} else if (field.isPackable() &&
|
||||
wireType == FieldSet.getWireFormatForFieldType(
|
||||
field.getLiteType(),
|
||||
true /* isPacked */)) {
|
||||
} else if (field.isPackable()
|
||||
&& wireType
|
||||
== FieldSet.getWireFormatForFieldType(field.getLiteType(), /* isPacked= */ true)) {
|
||||
packed = true;
|
||||
} else {
|
||||
unknown = true; // Unknown wire type.
|
||||
unknown = true; // Unknown wire type.
|
||||
}
|
||||
|
||||
if (unknown) { // Unknown field or wrong wire type. Skip.
|
||||
if (unknown) { // Unknown field or wrong wire type. Skip.
|
||||
if (unknownFields != null) {
|
||||
return unknownFields.mergeFieldFrom(tag, input);
|
||||
} else {
|
||||
@ -808,8 +766,8 @@ class MessageReflection {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final int rawValue = input.readEnum();
|
||||
if (field.getFile().supportsUnknownEnumValue()) {
|
||||
target.addRepeatedField(field,
|
||||
field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue));
|
||||
target.addRepeatedField(
|
||||
field, field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue));
|
||||
} else {
|
||||
final Object value = field.getEnumType().findValueByNumber(rawValue);
|
||||
if (value == null) {
|
||||
@ -822,8 +780,9 @@ class MessageReflection {
|
||||
}
|
||||
} else {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final Object value = WireFormat.readPrimitiveField(
|
||||
input, field.getLiteType(), target.getUtf8Validation(field));
|
||||
final Object value =
|
||||
WireFormat.readPrimitiveField(
|
||||
input, field.getLiteType(), target.getUtf8Validation(field));
|
||||
target.addRepeatedField(field, value);
|
||||
}
|
||||
}
|
||||
@ -831,16 +790,16 @@ class MessageReflection {
|
||||
} else {
|
||||
final Object value;
|
||||
switch (field.getType()) {
|
||||
case GROUP: {
|
||||
value = target
|
||||
.parseGroup(input, extensionRegistry, field, defaultInstance);
|
||||
break;
|
||||
}
|
||||
case MESSAGE: {
|
||||
value = target
|
||||
.parseMessage(input, extensionRegistry, field, defaultInstance);
|
||||
break;
|
||||
}
|
||||
case GROUP:
|
||||
{
|
||||
value = target.parseGroup(input, extensionRegistry, field, defaultInstance);
|
||||
break;
|
||||
}
|
||||
case MESSAGE:
|
||||
{
|
||||
value = target.parseMessage(input, extensionRegistry, field, defaultInstance);
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
final int rawValue = input.readEnum();
|
||||
if (field.getFile().supportsUnknownEnumValue()) {
|
||||
@ -858,8 +817,9 @@ class MessageReflection {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
value = WireFormat.readPrimitiveField(
|
||||
input, field.getLiteType(), target.getUtf8Validation(field));
|
||||
value =
|
||||
WireFormat.readPrimitiveField(
|
||||
input, field.getLiteType(), target.getUtf8Validation(field));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -873,16 +833,14 @@ class MessageReflection {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
|
||||
* MergeTarget.
|
||||
*/
|
||||
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into MergeTarget. */
|
||||
private static void mergeMessageSetExtensionFromCodedStream(
|
||||
CodedInputStream input,
|
||||
UnknownFieldSet.Builder unknownFields,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
Descriptors.Descriptor type,
|
||||
MergeTarget target) throws IOException {
|
||||
MergeTarget target)
|
||||
throws IOException {
|
||||
|
||||
// The wire format for MessageSet is:
|
||||
// message MessageSet {
|
||||
@ -921,19 +879,17 @@ class MessageReflection {
|
||||
// extensions of it. Otherwise we will treat the registry as if it
|
||||
// were empty.
|
||||
if (extensionRegistry instanceof ExtensionRegistry) {
|
||||
extension = target.findExtensionByNumber(
|
||||
(ExtensionRegistry) extensionRegistry, type, typeId);
|
||||
extension =
|
||||
target.findExtensionByNumber((ExtensionRegistry) extensionRegistry, type, typeId);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
|
||||
if (typeId != 0) {
|
||||
if (extension != null &&
|
||||
ExtensionRegistryLite.isEagerlyParseMessageSets()) {
|
||||
if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) {
|
||||
// We already know the type, so we can parse directly from the
|
||||
// input with no copying. Hooray!
|
||||
eagerlyMergeMessageSetExtension(
|
||||
input, extension, extensionRegistry, target);
|
||||
eagerlyMergeMessageSetExtension(input, extension, extensionRegistry, target);
|
||||
rawBytes = null;
|
||||
continue;
|
||||
}
|
||||
@ -952,12 +908,11 @@ class MessageReflection {
|
||||
// Process the raw bytes.
|
||||
if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
|
||||
if (extension != null) { // We known the type
|
||||
mergeMessageSetExtensionFromBytes(
|
||||
rawBytes, extension, extensionRegistry, target);
|
||||
mergeMessageSetExtensionFromBytes(rawBytes, extension, extensionRegistry, target);
|
||||
} else { // We don't know how to parse this. Ignore it.
|
||||
if (rawBytes != null && unknownFields != null) {
|
||||
unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
|
||||
.addLengthDelimited(rawBytes).build());
|
||||
unknownFields.mergeField(
|
||||
typeId, UnknownFieldSet.Field.newBuilder().addLengthDelimited(rawBytes).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -967,20 +922,21 @@ class MessageReflection {
|
||||
ByteString rawBytes,
|
||||
ExtensionRegistry.ExtensionInfo extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
MergeTarget target) throws IOException {
|
||||
MergeTarget target)
|
||||
throws IOException {
|
||||
|
||||
Descriptors.FieldDescriptor field = extension.descriptor;
|
||||
boolean hasOriginalValue = target.hasField(field);
|
||||
|
||||
if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
|
||||
// If the field already exists, we just parse the field.
|
||||
Object value = target.parseMessageFromBytes(
|
||||
rawBytes, extensionRegistry,field, extension.defaultInstance);
|
||||
Object value =
|
||||
target.parseMessageFromBytes(
|
||||
rawBytes, extensionRegistry, field, extension.defaultInstance);
|
||||
target.setField(field, value);
|
||||
} else {
|
||||
// Use LazyField to load MessageSet lazily.
|
||||
LazyField lazyField = new LazyField(
|
||||
extension.defaultInstance, extensionRegistry, rawBytes);
|
||||
LazyField lazyField = new LazyField(extension.defaultInstance, extensionRegistry, rawBytes);
|
||||
target.setField(field, lazyField);
|
||||
}
|
||||
}
|
||||
@ -989,10 +945,10 @@ class MessageReflection {
|
||||
CodedInputStream input,
|
||||
ExtensionRegistry.ExtensionInfo extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
MergeTarget target) throws IOException {
|
||||
MergeTarget target)
|
||||
throws IOException {
|
||||
Descriptors.FieldDescriptor field = extension.descriptor;
|
||||
Object value = target.parseMessage(input, extensionRegistry, field,
|
||||
extension.defaultInstance);
|
||||
Object value = target.parseMessage(input, extensionRegistry, field, extension.defaultInstance);
|
||||
target.setField(field, value);
|
||||
}
|
||||
}
|
||||
|
@ -30,19 +30,16 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Verifies that an object is mutable, throwing if not.
|
||||
*/
|
||||
/** Verifies that an object is mutable, throwing if not. */
|
||||
interface MutabilityOracle {
|
||||
static final MutabilityOracle IMMUTABLE = new MutabilityOracle() {
|
||||
@Override
|
||||
public void ensureMutable() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
static final MutabilityOracle IMMUTABLE =
|
||||
new MutabilityOracle() {
|
||||
@Override
|
||||
public void ensureMutable() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Throws an {@link UnsupportedOperationException} if not mutable.
|
||||
*/
|
||||
/** Throws an {@link UnsupportedOperationException} if not mutable. */
|
||||
void ensureMutable();
|
||||
}
|
||||
|
@ -44,9 +44,7 @@ import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link ByteString} that wraps around a {@link ByteBuffer}.
|
||||
*/
|
||||
/** A {@link ByteString} that wraps around a {@link ByteBuffer}. */
|
||||
final class NioByteString extends ByteString.LeafByteString {
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
@ -60,16 +58,12 @@ final class NioByteString extends ByteString.LeafByteString {
|
||||
// =================================================================
|
||||
// Serializable
|
||||
|
||||
/**
|
||||
* Magic method that lets us override serialization behavior.
|
||||
*/
|
||||
/** Magic method that lets us override serialization behavior. */
|
||||
private Object writeReplace() {
|
||||
return ByteString.copyFrom(buffer.slice());
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method that lets us override deserialization behavior.
|
||||
*/
|
||||
/** Magic method that lets us override deserialization behavior. */
|
||||
private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
|
||||
throw new InvalidObjectException("NioByteString instances are not to be serialized directly");
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import java.nio.ByteBuffer;
|
||||
/**
|
||||
* Abstract interface for parsing Protocol Messages.
|
||||
*
|
||||
* The implementation should be stateless and thread-safe.
|
||||
* <p>The implementation should be stateless and thread-safe.
|
||||
*
|
||||
* <p>All methods may throw {@link InvalidProtocolBufferException}. In the event of invalid data,
|
||||
* like an encoding error, the cause of the thrown exception will be {@code null}. However, if an
|
||||
@ -55,39 +55,31 @@ public interface Parser<MessageType> {
|
||||
/**
|
||||
* Parses a message of {@code MessageType} from the input.
|
||||
*
|
||||
* <p>Note: The caller should call
|
||||
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
|
||||
* verify that the last tag seen was the appropriate end-group tag,
|
||||
* or zero for EOF.
|
||||
* <p>Note: The caller should call {@link CodedInputStream#checkLastTagWas(int)} after calling
|
||||
* this to verify that the last tag seen was the appropriate end-group tag, or zero for EOF.
|
||||
*/
|
||||
public MessageType parseFrom(CodedInputStream input)
|
||||
public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(CodedInputStream)}, but also parses extensions. The extensions that you
|
||||
* want to be able to parse must be registered in {@code extensionRegistry}. Extensions not in the
|
||||
* registry will be treated as unknown fields.
|
||||
*/
|
||||
public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(CodedInputStream)}, but also parses extensions.
|
||||
* The extensions that you want to be able to parse must be registered in
|
||||
* {@code extensionRegistry}. Extensions not in the registry will be treated
|
||||
* as unknown fields.
|
||||
* Like {@link #parseFrom(CodedInputStream)}, but does not throw an exception if the message is
|
||||
* missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parseFrom(CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parsePartialFrom(CodedInputStream input) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(CodedInputStream)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(CodedInputStream input)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parsePartialFrom(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@ -106,180 +98,145 @@ public interface Parser<MessageType> {
|
||||
public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteString data)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(ByteString)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseFrom(ByteString)}, but does not throw an exception if the message is missing
|
||||
* required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(ByteString data)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)}, but does not throw an exception if
|
||||
* the message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}.
|
||||
*/
|
||||
public MessageType parseFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parseFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
public MessageType parseFrom(byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parseFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}.
|
||||
*/
|
||||
public MessageType parseFrom(byte[] data)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
public MessageType parseFrom(byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(byte[], int, int)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseFrom(byte[], int, int)}, but does not throw an exception if the message is
|
||||
* missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)}, but does not throw an exception if
|
||||
* the message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parsePartialFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(byte[])}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseFrom(byte[])}, but does not throw an exception if the message is missing
|
||||
* required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(byte[] data)
|
||||
public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(byte[], ExtensionRegistryLite)}, but does not throw an exception if the
|
||||
* message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(byte[], ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
* Parse a message of {@code MessageType} from {@code input}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}. Note that this method always reads the <i>entire</i>
|
||||
* input (unless it throws an exception). If you want it to stop earlier, you will need to wrap
|
||||
* your input in some wrapper stream that limits reading. Or, use {@link
|
||||
* MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your message and {@link
|
||||
* #parseDelimitedFrom(InputStream)} to read it.
|
||||
*
|
||||
* <p>Despite usually reading the entire input, this does not close the stream.
|
||||
*/
|
||||
public MessageType parsePartialFrom(byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse a message of {@code MessageType} from {@code input}.
|
||||
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
|
||||
* Note that this method always reads the <i>entire</i> input (unless it
|
||||
* throws an exception). If you want it to stop earlier, you will need to
|
||||
* wrap your input in some wrapper stream that limits reading. Or, use
|
||||
* {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your
|
||||
* message and {@link #parseDelimitedFrom(InputStream)} to read it.
|
||||
* <p>
|
||||
* Despite usually reading the entire input, this does not close the stream.
|
||||
*/
|
||||
public MessageType parseFrom(InputStream input)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses a message of {@code MessageType} from {@code input}.
|
||||
* This is just a small wrapper around
|
||||
* Parses a message of {@code MessageType} from {@code input}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
public MessageType parseFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(InputStream)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseFrom(InputStream)}, but does not throw an exception if the message is missing
|
||||
* required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(InputStream input)
|
||||
throws InvalidProtocolBufferException;
|
||||
public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(InputStream, ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
* Like {@link #parseFrom(InputStream, ExtensionRegistryLite)}, but does not throw an exception if
|
||||
* the message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(InputStream)}, but does not read util EOF.
|
||||
* Instead, the size of message (encoded as a varint) is read first,
|
||||
* then the message data. Use
|
||||
* {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write
|
||||
* messages in this format.
|
||||
* Like {@link #parseFrom(InputStream)}, but does not read util EOF. Instead, the size of message
|
||||
* (encoded as a varint) is read first, then the message data. Use {@link
|
||||
* MessageLite#writeDelimitedTo(java.io.OutputStream)} to write messages in this format.
|
||||
*
|
||||
* @return Parsed message if successful, or null if the stream is at EOF when
|
||||
* the method starts. Any other error (including reaching EOF during
|
||||
* parsing) will cause an exception to be thrown.
|
||||
* @return Parsed message if successful, or null if the stream is at EOF when the method starts.
|
||||
* Any other error (including reaching EOF during parsing) will cause an exception to be
|
||||
* thrown.
|
||||
*/
|
||||
public MessageType parseDelimitedFrom(InputStream input)
|
||||
public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException;
|
||||
|
||||
/** Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions. */
|
||||
public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions.
|
||||
*/
|
||||
public MessageType parseDelimitedFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial
|
||||
* message is returned.
|
||||
* Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an exception if the message
|
||||
* is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialDelimitedFrom(InputStream input)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)},
|
||||
* but does not throw an exception if the message is missing required fields.
|
||||
* Instead, a partial message is returned.
|
||||
* Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)}, but does not throw an
|
||||
* exception if the message is missing required fields. Instead, a partial message is returned.
|
||||
*/
|
||||
public MessageType parsePartialDelimitedFrom(
|
||||
InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
}
|
||||
|
@ -31,31 +31,29 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implements {@link ProtobufList} for non-primitive and {@link String} types.
|
||||
*/
|
||||
/** Implements {@link ProtobufList} for non-primitive and {@link String} types. */
|
||||
final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
|
||||
|
||||
private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked") // Guaranteed safe by runtime.
|
||||
public static <E> ProtobufArrayList<E> emptyList() {
|
||||
return (ProtobufArrayList<E>) EMPTY_LIST;
|
||||
}
|
||||
|
||||
|
||||
private final List<E> list;
|
||||
|
||||
ProtobufArrayList() {
|
||||
this(new ArrayList<E>(DEFAULT_CAPACITY));
|
||||
}
|
||||
|
||||
|
||||
private ProtobufArrayList(List<E> list) {
|
||||
this.list = list;
|
||||
}
|
||||
@ -69,7 +67,7 @@ final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
|
||||
newList.addAll(list);
|
||||
return new ProtobufArrayList<E>(newList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
ensureIsMutable();
|
||||
@ -81,7 +79,7 @@ final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
|
||||
public E get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
ensureIsMutable();
|
||||
@ -89,7 +87,7 @@ final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
|
||||
modCount++;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
ensureIsMutable();
|
||||
|
@ -33,27 +33,20 @@ package com.google.protobuf;
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
|
||||
/**
|
||||
* Interface of useful methods added to all enums generated by the protocol
|
||||
* compiler.
|
||||
*/
|
||||
/** Interface of useful methods added to all enums generated by the protocol compiler. */
|
||||
public interface ProtocolMessageEnum extends Internal.EnumLite {
|
||||
|
||||
/**
|
||||
* Return the value's numeric value as defined in the .proto file.
|
||||
*/
|
||||
/** Return the value's numeric value as defined in the .proto file. */
|
||||
@Override
|
||||
int getNumber();
|
||||
|
||||
/**
|
||||
* Return the value's descriptor, which contains information such as
|
||||
* value name, number, and type.
|
||||
* Return the value's descriptor, which contains information such as value name, number, and type.
|
||||
*/
|
||||
EnumValueDescriptor getValueDescriptor();
|
||||
|
||||
/**
|
||||
* Return the enum type's descriptor, which contains information
|
||||
* about each defined value, etc.
|
||||
* Return the enum type's descriptor, which contains information about each defined value, etc.
|
||||
*/
|
||||
EnumDescriptor getDescriptorForType();
|
||||
}
|
||||
|
@ -33,16 +33,14 @@ package com.google.protobuf;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An interface extending {@code List<String>} used for repeated string fields
|
||||
* to provide optional access to the data as a list of ByteStrings. The
|
||||
* underlying implementation stores values as either ByteStrings or Strings
|
||||
* (see {@link LazyStringArrayList}) depending on how the value was initialized
|
||||
* or last read, and it is often more efficient to deal with lists of
|
||||
* ByteStrings when handling protos that have been deserialized from bytes.
|
||||
* An interface extending {@code List<String>} used for repeated string fields to provide optional
|
||||
* access to the data as a list of ByteStrings. The underlying implementation stores values as
|
||||
* either ByteStrings or Strings (see {@link LazyStringArrayList}) depending on how the value was
|
||||
* initialized or last read, and it is often more efficient to deal with lists of ByteStrings when
|
||||
* handling protos that have been deserialized from bytes.
|
||||
*/
|
||||
public interface ProtocolStringList extends List<String> {
|
||||
|
||||
/** Returns a view of the data as a list of ByteStrings. */
|
||||
List<ByteString> asByteStringList();
|
||||
|
||||
}
|
||||
|
@ -39,36 +39,29 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@code RepeatedFieldBuilder} implements a structure that a protocol
|
||||
* message uses to hold a repeated field of other protocol messages. It supports
|
||||
* the classical use case of adding immutable {@link Message}'s to the
|
||||
* repeated field and is highly optimized around this (no extra memory
|
||||
* allocations and sharing of immutable arrays).
|
||||
* <br>
|
||||
* It also supports the additional use case of adding a {@link Message.Builder}
|
||||
* to the repeated field and deferring conversion of that {@code Builder}
|
||||
* to an immutable {@code Message}. In this way, it's possible to maintain
|
||||
* a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure.
|
||||
* <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree
|
||||
* to messages when build is called on the root or when any method is called
|
||||
* that desires a Message instead of a Builder. In terms of the implementation,
|
||||
* the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
|
||||
* classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its
|
||||
* descendants.
|
||||
* {@code RepeatedFieldBuilder} implements a structure that a protocol message uses to hold a
|
||||
* repeated field of other protocol messages. It supports the classical use case of adding immutable
|
||||
* {@link Message}'s to the repeated field and is highly optimized around this (no extra memory
|
||||
* allocations and sharing of immutable arrays). <br>
|
||||
* It also supports the additional use case of adding a {@link Message.Builder} to the repeated
|
||||
* field and deferring conversion of that {@code Builder} to an immutable {@code Message}. In this
|
||||
* way, it's possible to maintain a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure. <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree to messages when
|
||||
* build is called on the root or when any method is called that desires a Message instead of a
|
||||
* Builder. In terms of the implementation, the {@code SingleFieldBuilder} and {@code
|
||||
* RepeatedFieldBuilder} classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its descendants.
|
||||
*
|
||||
* @param <MType> the type of message for the field
|
||||
* @param <BType> the type of builder for the field
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class RepeatedFieldBuilder
|
||||
<MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
public class RepeatedFieldBuilder<
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
implements GeneratedMessage.BuilderParent {
|
||||
|
||||
// Parent to send changes to.
|
||||
@ -120,8 +113,7 @@ public class RepeatedFieldBuilder
|
||||
// is fully backed by this object and all changes are reflected in it.
|
||||
// Access to any item returns either a builder or message depending on
|
||||
// what is most efficient.
|
||||
private MessageOrBuilderExternalList<MType, BType, IType>
|
||||
externalMessageOrBuilderList;
|
||||
private MessageOrBuilderExternalList<MType, BType, IType> externalMessageOrBuilderList;
|
||||
|
||||
/**
|
||||
* Constructs a new builder with an empty list of messages.
|
||||
@ -148,8 +140,8 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the list of messages is mutable so it can be updated. If it's
|
||||
* immutable, a copy is made.
|
||||
* Ensures that the list of messages is mutable so it can be updated. If it's immutable, a copy is
|
||||
* made.
|
||||
*/
|
||||
private void ensureMutableMessageList() {
|
||||
if (!isMessagesListMutable) {
|
||||
@ -159,15 +151,12 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the list of builders is not null. If it's null, the list is
|
||||
* created and initialized to be the same size as the messages list with
|
||||
* null entries.
|
||||
* Ensures that the list of builders is not null. If it's null, the list is created and
|
||||
* initialized to be the same size as the messages list with null entries.
|
||||
*/
|
||||
private void ensureBuilders() {
|
||||
if (this.builders == null) {
|
||||
this.builders =
|
||||
new ArrayList<SingleFieldBuilder<MType, BType, IType>>(
|
||||
messages.size());
|
||||
this.builders = new ArrayList<SingleFieldBuilder<MType, BType, IType>>(messages.size());
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
builders.add(null);
|
||||
}
|
||||
@ -193,9 +182,9 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message at the specified index. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it.
|
||||
* Get the message at the specified index. If the message is currently stored as a {@code
|
||||
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
|
||||
* on it.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return the message for the specified index
|
||||
@ -205,13 +194,13 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message at the specified index. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it.
|
||||
* Get the message at the specified index. If the message is currently stored as a {@code
|
||||
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
|
||||
* on it.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @param forBuild this is being called for build so we want to make sure
|
||||
* we SingleFieldBuilder.build to send dirty invalidations
|
||||
* @param forBuild this is being called for build so we want to make sure we
|
||||
* SingleFieldBuilder.build to send dirty invalidations
|
||||
* @return the message for the specified index
|
||||
*/
|
||||
private MType getMessage(int index, boolean forBuild) {
|
||||
@ -235,9 +224,8 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a builder for the specified index. If no builder has been created for
|
||||
* that index, a builder is created on demand by calling
|
||||
* {@link Message#toBuilder}.
|
||||
* Gets a builder for the specified index. If no builder has been created for that index, a
|
||||
* builder is created on demand by calling {@link Message#toBuilder}.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return The builder for that index
|
||||
@ -247,16 +235,15 @@ public class RepeatedFieldBuilder
|
||||
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
|
||||
if (builder == null) {
|
||||
MType message = messages.get(index);
|
||||
builder = new SingleFieldBuilder<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
builder = new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
|
||||
builders.set(index, builder);
|
||||
}
|
||||
return builder.getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class interface for the specified index. This may either be
|
||||
* a builder or a message. It will return whatever is more efficient.
|
||||
* Gets the base class interface for the specified index. This may either be a builder or a
|
||||
* message. It will return whatever is more efficient.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return the message or builder for the index as the base class interface
|
||||
@ -283,21 +270,18 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a message at the specified index replacing the existing item at
|
||||
* that index.
|
||||
* Sets a message at the specified index replacing the existing item at that index.
|
||||
*
|
||||
* @param index the index to set.
|
||||
* @param message the message to set
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilder<MType, BType, IType> setMessage(
|
||||
int index, MType message) {
|
||||
public RepeatedFieldBuilder<MType, BType, IType> setMessage(int index, MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.set(index, message);
|
||||
if (builders != null) {
|
||||
SingleFieldBuilder<MType, BType, IType> entry =
|
||||
builders.set(index, null);
|
||||
SingleFieldBuilder<MType, BType, IType> entry = builders.set(index, null);
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -313,8 +297,7 @@ public class RepeatedFieldBuilder
|
||||
* @param message the message to add
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage(
|
||||
MType message) {
|
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage(MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(message);
|
||||
@ -327,16 +310,15 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified message at the specified position in this list.
|
||||
* Shifts the element currently at that position (if any) and any subsequent
|
||||
* elements to the right (adds one to their indices).
|
||||
* Inserts the specified message at the specified position in this list. Shifts the element
|
||||
* currently at that position (if any) and any subsequent elements to the right (adds one to their
|
||||
* indices).
|
||||
*
|
||||
* @param index the index at which to insert the message
|
||||
* @param message the message to add
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage(
|
||||
int index, MType message) {
|
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage(int index, MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(index, message);
|
||||
@ -349,9 +331,8 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends all of the messages in the specified collection to the end of
|
||||
* this list, in the order that they are returned by the specified
|
||||
* collection's iterator.
|
||||
* Appends all of the messages in the specified collection to the end of this list, in the order
|
||||
* that they are returned by the specified collection's iterator.
|
||||
*
|
||||
* @param values the messages to add
|
||||
* @return the builder
|
||||
@ -365,8 +346,8 @@ public class RepeatedFieldBuilder
|
||||
// If we can inspect the size, we can more efficiently add messages.
|
||||
int size = -1;
|
||||
if (values instanceof Collection) {
|
||||
@SuppressWarnings("unchecked") final
|
||||
Collection<MType> collection = (Collection<MType>) values;
|
||||
@SuppressWarnings("unchecked")
|
||||
final Collection<MType> collection = (Collection<MType>) values;
|
||||
if (collection.size() == 0) {
|
||||
return this;
|
||||
}
|
||||
@ -375,8 +356,7 @@ public class RepeatedFieldBuilder
|
||||
ensureMutableMessageList();
|
||||
|
||||
if (size >= 0 && messages instanceof ArrayList) {
|
||||
((ArrayList<MType>) messages)
|
||||
.ensureCapacity(messages.size() + size);
|
||||
((ArrayList<MType>) messages).ensureCapacity(messages.size() + size);
|
||||
}
|
||||
|
||||
for (MType value : values) {
|
||||
@ -398,8 +378,7 @@ public class RepeatedFieldBuilder
|
||||
ensureMutableMessageList();
|
||||
ensureBuilders();
|
||||
SingleFieldBuilder<MType, BType, IType> builder =
|
||||
new SingleFieldBuilder<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
|
||||
messages.add(null);
|
||||
builders.add(builder);
|
||||
onChanged();
|
||||
@ -408,9 +387,8 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new builder at the specified position in this list.
|
||||
* Shifts the element currently at that position (if any) and any subsequent
|
||||
* elements to the right (adds one to their indices).
|
||||
* Inserts a new builder at the specified position in this list. Shifts the element currently at
|
||||
* that position (if any) and any subsequent elements to the right (adds one to their indices).
|
||||
*
|
||||
* @param index the index at which to insert the builder
|
||||
* @param message the message to add which is the basis of the builder
|
||||
@ -420,8 +398,7 @@ public class RepeatedFieldBuilder
|
||||
ensureMutableMessageList();
|
||||
ensureBuilders();
|
||||
SingleFieldBuilder<MType, BType, IType> builder =
|
||||
new SingleFieldBuilder<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
|
||||
messages.add(index, null);
|
||||
builders.add(index, builder);
|
||||
onChanged();
|
||||
@ -430,9 +407,9 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specified position in this list. Shifts any
|
||||
* subsequent elements to the left (subtracts one from their indices).
|
||||
* Returns the element that was removed from the list.
|
||||
* Removes the element at the specified position in this list. Shifts any subsequent elements to
|
||||
* the left (subtracts one from their indices). Returns the element that was removed from the
|
||||
* list.
|
||||
*
|
||||
* @param index the index at which to remove the message
|
||||
*/
|
||||
@ -440,8 +417,7 @@ public class RepeatedFieldBuilder
|
||||
ensureMutableMessageList();
|
||||
messages.remove(index);
|
||||
if (builders != null) {
|
||||
SingleFieldBuilder<MType, BType, IType> entry =
|
||||
builders.remove(index);
|
||||
SingleFieldBuilder<MType, BType, IType> entry = builders.remove(index);
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -450,16 +426,12 @@ public class RepeatedFieldBuilder
|
||||
incrementModCounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the elements from this list.
|
||||
* The list will be empty after this call returns.
|
||||
*/
|
||||
/** Removes all of the elements from this list. The list will be empty after this call returns. */
|
||||
public void clear() {
|
||||
messages = Collections.emptyList();
|
||||
isMessagesListMutable = false;
|
||||
if (builders != null) {
|
||||
for (SingleFieldBuilder<MType, BType, IType> entry :
|
||||
builders) {
|
||||
for (SingleFieldBuilder<MType, BType, IType> entry : builders) {
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -519,50 +491,47 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of messages. The returned list is live
|
||||
* and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of messages. The returned list is live and will reflect
|
||||
* any changes to the underlying builder.
|
||||
*
|
||||
* @return the messages in the list
|
||||
*/
|
||||
public List<MType> getMessageList() {
|
||||
if (externalMessageList == null) {
|
||||
externalMessageList =
|
||||
new MessageExternalList<MType, BType, IType>(this);
|
||||
externalMessageList = new MessageExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalMessageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of builders. This returned list is
|
||||
* live and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of builders. This returned list is live and will reflect
|
||||
* any changes to the underlying builder.
|
||||
*
|
||||
* @return the builders in the list
|
||||
*/
|
||||
public List<BType> getBuilderList() {
|
||||
if (externalBuilderList == null) {
|
||||
externalBuilderList =
|
||||
new BuilderExternalList<MType, BType, IType>(this);
|
||||
externalBuilderList = new BuilderExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalBuilderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of MessageOrBuilders. This returned
|
||||
* list is live and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of MessageOrBuilders. This returned list is live and will
|
||||
* reflect any changes to the underlying builder.
|
||||
*
|
||||
* @return the builders in the list
|
||||
*/
|
||||
public List<IType> getMessageOrBuilderList() {
|
||||
if (externalMessageOrBuilderList == null) {
|
||||
externalMessageOrBuilderList =
|
||||
new MessageOrBuilderExternalList<MType, BType, IType>(this);
|
||||
externalMessageOrBuilderList = new MessageOrBuilderExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalMessageOrBuilderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a the builder or one of its nested children has changed
|
||||
* and any parent should be notified of its invalidation.
|
||||
* Called when a the builder or one of its nested children has changed and any parent should be
|
||||
* notified of its invalidation.
|
||||
*/
|
||||
private void onChanged() {
|
||||
if (isClean && parent != null) {
|
||||
@ -579,9 +548,8 @@ public class RepeatedFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the mod counts so that an ConcurrentModificationException can
|
||||
* be thrown if calling code tries to modify the builder while its iterating
|
||||
* the list.
|
||||
* Increments the mod counts so that an ConcurrentModificationException can be thrown if calling
|
||||
* code tries to modify the builder while its iterating the list.
|
||||
*/
|
||||
private void incrementModCounts() {
|
||||
if (externalMessageList != null) {
|
||||
@ -603,15 +571,14 @@ public class RepeatedFieldBuilder
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class MessageExternalList<
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<MType> implements List<MType> {
|
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder;
|
||||
|
||||
MessageExternalList(
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
MessageExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@ -638,15 +605,14 @@ public class RepeatedFieldBuilder
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class BuilderExternalList<
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<BType> implements List<BType> {
|
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder;
|
||||
|
||||
BuilderExternalList(
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
BuilderExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@ -673,15 +639,14 @@ public class RepeatedFieldBuilder
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class MessageOrBuilderExternalList<
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<IType> implements List<IType> {
|
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder;
|
||||
|
||||
MessageOrBuilderExternalList(
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
MessageOrBuilderExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
|
@ -39,36 +39,29 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@code RepeatedFieldBuilderV3} implements a structure that a protocol
|
||||
* message uses to hold a repeated field of other protocol messages. It supports
|
||||
* the classical use case of adding immutable {@link Message}'s to the
|
||||
* repeated field and is highly optimized around this (no extra memory
|
||||
* allocations and sharing of immutable arrays).
|
||||
* <br>
|
||||
* It also supports the additional use case of adding a {@link Message.Builder}
|
||||
* to the repeated field and deferring conversion of that {@code Builder}
|
||||
* to an immutable {@code Message}. In this way, it's possible to maintain
|
||||
* a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure.
|
||||
* <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree
|
||||
* to messages when build is called on the root or when any method is called
|
||||
* that desires a Message instead of a Builder. In terms of the implementation,
|
||||
* the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
|
||||
* classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its
|
||||
* descendants.
|
||||
* {@code RepeatedFieldBuilderV3} implements a structure that a protocol message uses to hold a
|
||||
* repeated field of other protocol messages. It supports the classical use case of adding immutable
|
||||
* {@link Message}'s to the repeated field and is highly optimized around this (no extra memory
|
||||
* allocations and sharing of immutable arrays). <br>
|
||||
* It also supports the additional use case of adding a {@link Message.Builder} to the repeated
|
||||
* field and deferring conversion of that {@code Builder} to an immutable {@code Message}. In this
|
||||
* way, it's possible to maintain a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure. <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree to messages when
|
||||
* build is called on the root or when any method is called that desires a Message instead of a
|
||||
* Builder. In terms of the implementation, the {@code SingleFieldBuilderV3} and {@code
|
||||
* RepeatedFieldBuilderV3} classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its descendants.
|
||||
*
|
||||
* @param <MType> the type of message for the field
|
||||
* @param <BType> the type of builder for the field
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class RepeatedFieldBuilderV3
|
||||
<MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
public class RepeatedFieldBuilderV3<
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
implements AbstractMessage.BuilderParent {
|
||||
|
||||
// Parent to send changes to.
|
||||
@ -120,8 +113,7 @@ public class RepeatedFieldBuilderV3
|
||||
// is fully backed by this object and all changes are reflected in it.
|
||||
// Access to any item returns either a builder or message depending on
|
||||
// what is most efficient.
|
||||
private MessageOrBuilderExternalList<MType, BType, IType>
|
||||
externalMessageOrBuilderList;
|
||||
private MessageOrBuilderExternalList<MType, BType, IType> externalMessageOrBuilderList;
|
||||
|
||||
/**
|
||||
* Constructs a new builder with an empty list of messages.
|
||||
@ -148,8 +140,8 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the list of messages is mutable so it can be updated. If it's
|
||||
* immutable, a copy is made.
|
||||
* Ensures that the list of messages is mutable so it can be updated. If it's immutable, a copy is
|
||||
* made.
|
||||
*/
|
||||
private void ensureMutableMessageList() {
|
||||
if (!isMessagesListMutable) {
|
||||
@ -159,15 +151,12 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the list of builders is not null. If it's null, the list is
|
||||
* created and initialized to be the same size as the messages list with
|
||||
* null entries.
|
||||
* Ensures that the list of builders is not null. If it's null, the list is created and
|
||||
* initialized to be the same size as the messages list with null entries.
|
||||
*/
|
||||
private void ensureBuilders() {
|
||||
if (this.builders == null) {
|
||||
this.builders =
|
||||
new ArrayList<SingleFieldBuilderV3<MType, BType, IType>>(
|
||||
messages.size());
|
||||
this.builders = new ArrayList<SingleFieldBuilderV3<MType, BType, IType>>(messages.size());
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
builders.add(null);
|
||||
}
|
||||
@ -193,9 +182,9 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message at the specified index. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it.
|
||||
* Get the message at the specified index. If the message is currently stored as a {@code
|
||||
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
|
||||
* on it.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return the message for the specified index
|
||||
@ -205,13 +194,13 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message at the specified index. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it.
|
||||
* Get the message at the specified index. If the message is currently stored as a {@code
|
||||
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
|
||||
* on it.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @param forBuild this is being called for build so we want to make sure
|
||||
* we SingleFieldBuilderV3.build to send dirty invalidations
|
||||
* @param forBuild this is being called for build so we want to make sure we
|
||||
* SingleFieldBuilderV3.build to send dirty invalidations
|
||||
* @return the message for the specified index
|
||||
*/
|
||||
private MType getMessage(int index, boolean forBuild) {
|
||||
@ -235,9 +224,8 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a builder for the specified index. If no builder has been created for
|
||||
* that index, a builder is created on demand by calling
|
||||
* {@link Message#toBuilder}.
|
||||
* Gets a builder for the specified index. If no builder has been created for that index, a
|
||||
* builder is created on demand by calling {@link Message#toBuilder}.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return The builder for that index
|
||||
@ -247,16 +235,15 @@ public class RepeatedFieldBuilderV3
|
||||
SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
|
||||
if (builder == null) {
|
||||
MType message = messages.get(index);
|
||||
builder = new SingleFieldBuilderV3<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
builder = new SingleFieldBuilderV3<MType, BType, IType>(message, this, isClean);
|
||||
builders.set(index, builder);
|
||||
}
|
||||
return builder.getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class interface for the specified index. This may either be
|
||||
* a builder or a message. It will return whatever is more efficient.
|
||||
* Gets the base class interface for the specified index. This may either be a builder or a
|
||||
* message. It will return whatever is more efficient.
|
||||
*
|
||||
* @param index the index of the message to get
|
||||
* @return the message or builder for the index as the base class interface
|
||||
@ -283,21 +270,18 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a message at the specified index replacing the existing item at
|
||||
* that index.
|
||||
* Sets a message at the specified index replacing the existing item at that index.
|
||||
*
|
||||
* @param index the index to set.
|
||||
* @param message the message to set
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
|
||||
int index, MType message) {
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(int index, MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.set(index, message);
|
||||
if (builders != null) {
|
||||
SingleFieldBuilderV3<MType, BType, IType> entry =
|
||||
builders.set(index, null);
|
||||
SingleFieldBuilderV3<MType, BType, IType> entry = builders.set(index, null);
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -313,8 +297,7 @@ public class RepeatedFieldBuilderV3
|
||||
* @param message the message to add
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
|
||||
MType message) {
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(message);
|
||||
@ -327,16 +310,15 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified message at the specified position in this list.
|
||||
* Shifts the element currently at that position (if any) and any subsequent
|
||||
* elements to the right (adds one to their indices).
|
||||
* Inserts the specified message at the specified position in this list. Shifts the element
|
||||
* currently at that position (if any) and any subsequent elements to the right (adds one to their
|
||||
* indices).
|
||||
*
|
||||
* @param index the index at which to insert the message
|
||||
* @param message the message to add
|
||||
* @return the builder
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
|
||||
int index, MType message) {
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(int index, MType message) {
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(index, message);
|
||||
@ -349,9 +331,8 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends all of the messages in the specified collection to the end of
|
||||
* this list, in the order that they are returned by the specified
|
||||
* collection's iterator.
|
||||
* Appends all of the messages in the specified collection to the end of this list, in the order
|
||||
* that they are returned by the specified collection's iterator.
|
||||
*
|
||||
* @param values the messages to add
|
||||
* @return the builder
|
||||
@ -365,8 +346,8 @@ public class RepeatedFieldBuilderV3
|
||||
// If we can inspect the size, we can more efficiently add messages.
|
||||
int size = -1;
|
||||
if (values instanceof Collection) {
|
||||
@SuppressWarnings("unchecked") final
|
||||
Collection<MType> collection = (Collection<MType>) values;
|
||||
@SuppressWarnings("unchecked")
|
||||
final Collection<MType> collection = (Collection<MType>) values;
|
||||
if (collection.size() == 0) {
|
||||
return this;
|
||||
}
|
||||
@ -375,8 +356,7 @@ public class RepeatedFieldBuilderV3
|
||||
ensureMutableMessageList();
|
||||
|
||||
if (size >= 0 && messages instanceof ArrayList) {
|
||||
((ArrayList<MType>) messages)
|
||||
.ensureCapacity(messages.size() + size);
|
||||
((ArrayList<MType>) messages).ensureCapacity(messages.size() + size);
|
||||
}
|
||||
|
||||
for (MType value : values) {
|
||||
@ -398,8 +378,7 @@ public class RepeatedFieldBuilderV3
|
||||
ensureMutableMessageList();
|
||||
ensureBuilders();
|
||||
SingleFieldBuilderV3<MType, BType, IType> builder =
|
||||
new SingleFieldBuilderV3<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
new SingleFieldBuilderV3<MType, BType, IType>(message, this, isClean);
|
||||
messages.add(null);
|
||||
builders.add(builder);
|
||||
onChanged();
|
||||
@ -408,9 +387,8 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new builder at the specified position in this list.
|
||||
* Shifts the element currently at that position (if any) and any subsequent
|
||||
* elements to the right (adds one to their indices).
|
||||
* Inserts a new builder at the specified position in this list. Shifts the element currently at
|
||||
* that position (if any) and any subsequent elements to the right (adds one to their indices).
|
||||
*
|
||||
* @param index the index at which to insert the builder
|
||||
* @param message the message to add which is the basis of the builder
|
||||
@ -420,8 +398,7 @@ public class RepeatedFieldBuilderV3
|
||||
ensureMutableMessageList();
|
||||
ensureBuilders();
|
||||
SingleFieldBuilderV3<MType, BType, IType> builder =
|
||||
new SingleFieldBuilderV3<MType, BType, IType>(
|
||||
message, this, isClean);
|
||||
new SingleFieldBuilderV3<MType, BType, IType>(message, this, isClean);
|
||||
messages.add(index, null);
|
||||
builders.add(index, builder);
|
||||
onChanged();
|
||||
@ -430,9 +407,9 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specified position in this list. Shifts any
|
||||
* subsequent elements to the left (subtracts one from their indices).
|
||||
* Returns the element that was removed from the list.
|
||||
* Removes the element at the specified position in this list. Shifts any subsequent elements to
|
||||
* the left (subtracts one from their indices). Returns the element that was removed from the
|
||||
* list.
|
||||
*
|
||||
* @param index the index at which to remove the message
|
||||
*/
|
||||
@ -440,8 +417,7 @@ public class RepeatedFieldBuilderV3
|
||||
ensureMutableMessageList();
|
||||
messages.remove(index);
|
||||
if (builders != null) {
|
||||
SingleFieldBuilderV3<MType, BType, IType> entry =
|
||||
builders.remove(index);
|
||||
SingleFieldBuilderV3<MType, BType, IType> entry = builders.remove(index);
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -450,16 +426,12 @@ public class RepeatedFieldBuilderV3
|
||||
incrementModCounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the elements from this list.
|
||||
* The list will be empty after this call returns.
|
||||
*/
|
||||
/** Removes all of the elements from this list. The list will be empty after this call returns. */
|
||||
public void clear() {
|
||||
messages = Collections.emptyList();
|
||||
isMessagesListMutable = false;
|
||||
if (builders != null) {
|
||||
for (SingleFieldBuilderV3<MType, BType, IType> entry :
|
||||
builders) {
|
||||
for (SingleFieldBuilderV3<MType, BType, IType> entry : builders) {
|
||||
if (entry != null) {
|
||||
entry.dispose();
|
||||
}
|
||||
@ -519,50 +491,47 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of messages. The returned list is live
|
||||
* and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of messages. The returned list is live and will reflect
|
||||
* any changes to the underlying builder.
|
||||
*
|
||||
* @return the messages in the list
|
||||
*/
|
||||
public List<MType> getMessageList() {
|
||||
if (externalMessageList == null) {
|
||||
externalMessageList =
|
||||
new MessageExternalList<MType, BType, IType>(this);
|
||||
externalMessageList = new MessageExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalMessageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of builders. This returned list is
|
||||
* live and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of builders. This returned list is live and will reflect
|
||||
* any changes to the underlying builder.
|
||||
*
|
||||
* @return the builders in the list
|
||||
*/
|
||||
public List<BType> getBuilderList() {
|
||||
if (externalBuilderList == null) {
|
||||
externalBuilderList =
|
||||
new BuilderExternalList<MType, BType, IType>(this);
|
||||
externalBuilderList = new BuilderExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalBuilderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a view of the builder as a list of MessageOrBuilders. This returned
|
||||
* list is live and will reflect any changes to the underlying builder.
|
||||
* Gets a view of the builder as a list of MessageOrBuilders. This returned list is live and will
|
||||
* reflect any changes to the underlying builder.
|
||||
*
|
||||
* @return the builders in the list
|
||||
*/
|
||||
public List<IType> getMessageOrBuilderList() {
|
||||
if (externalMessageOrBuilderList == null) {
|
||||
externalMessageOrBuilderList =
|
||||
new MessageOrBuilderExternalList<MType, BType, IType>(this);
|
||||
externalMessageOrBuilderList = new MessageOrBuilderExternalList<MType, BType, IType>(this);
|
||||
}
|
||||
return externalMessageOrBuilderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a the builder or one of its nested children has changed
|
||||
* and any parent should be notified of its invalidation.
|
||||
* Called when a the builder or one of its nested children has changed and any parent should be
|
||||
* notified of its invalidation.
|
||||
*/
|
||||
private void onChanged() {
|
||||
if (isClean && parent != null) {
|
||||
@ -579,9 +548,8 @@ public class RepeatedFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the mod counts so that an ConcurrentModificationException can
|
||||
* be thrown if calling code tries to modify the builder while its iterating
|
||||
* the list.
|
||||
* Increments the mod counts so that an ConcurrentModificationException can be thrown if calling
|
||||
* code tries to modify the builder while its iterating the list.
|
||||
*/
|
||||
private void incrementModCounts() {
|
||||
if (externalMessageList != null) {
|
||||
@ -603,15 +571,14 @@ public class RepeatedFieldBuilderV3
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class MessageExternalList<
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<MType> implements List<MType> {
|
||||
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder;
|
||||
|
||||
MessageExternalList(
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
MessageExternalList(RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@ -638,15 +605,14 @@ public class RepeatedFieldBuilderV3
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class BuilderExternalList<
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<BType> implements List<BType> {
|
||||
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder;
|
||||
|
||||
BuilderExternalList(
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
BuilderExternalList(RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@ -673,15 +639,14 @@ public class RepeatedFieldBuilderV3
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*/
|
||||
private static class MessageOrBuilderExternalList<
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
extends AbstractList<IType> implements List<IType> {
|
||||
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder;
|
||||
|
||||
MessageOrBuilderExternalList(
|
||||
RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
MessageOrBuilderExternalList(RepeatedFieldBuilderV3<MType, BType, IType> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
|
@ -46,41 +46,35 @@ import java.util.NoSuchElementException;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Class to represent {@code ByteStrings} formed by concatenation of other
|
||||
* ByteStrings, without copying the data in the pieces. The concatenation is
|
||||
* represented as a tree whose leaf nodes are each a
|
||||
* {@link com.google.protobuf.ByteString.LeafByteString}.
|
||||
* Class to represent {@code ByteStrings} formed by concatenation of other ByteStrings, without
|
||||
* copying the data in the pieces. The concatenation is represented as a tree whose leaf nodes are
|
||||
* each a {@link com.google.protobuf.ByteString.LeafByteString}.
|
||||
*
|
||||
* <p>Most of the operation here is inspired by the now-famous paper <a
|
||||
* href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
|
||||
* BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
|
||||
* michael plass
|
||||
* BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and michael plass
|
||||
*
|
||||
* <p>The algorithms described in the paper have been implemented for character
|
||||
* strings in {@code com.google.common.string.Rope} and in the c++ class {@code
|
||||
* cord.cc}.
|
||||
* <p>The algorithms described in the paper have been implemented for character strings in {@code
|
||||
* com.google.common.string.Rope} and in the c++ class {@code cord.cc}.
|
||||
*
|
||||
* <p>Fundamentally the Rope algorithm represents the collection of pieces as a
|
||||
* binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
|
||||
* sequence length, sequences that are too short relative to their depth cause a
|
||||
* tree rebalance. More precisely, a tree of depth d is "balanced" in the
|
||||
* terminology of BAP95 if its length is at least F(d+2), where F(n) is the
|
||||
* n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum
|
||||
* lengths 1, 2, 3, 5, 8, 13,...
|
||||
* <p>Fundamentally the Rope algorithm represents the collection of pieces as a binary tree. BAP95
|
||||
* uses a Fibonacci bound relating depth to a minimum sequence length, sequences that are too short
|
||||
* relative to their depth cause a tree rebalance. More precisely, a tree of depth d is "balanced"
|
||||
* in the terminology of BAP95 if its length is at least F(d+2), where F(n) is the n-the Fibonacci
|
||||
* number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum lengths 1, 2, 3, 5, 8, 13,...
|
||||
*
|
||||
* @author carlanton@google.com (Carl Haverl)
|
||||
*/
|
||||
final class RopeByteString extends ByteString {
|
||||
|
||||
/**
|
||||
* BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
|
||||
* depth n is "balanced", i.e flat enough, if its length is at least Fn+2,
|
||||
* e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at
|
||||
* least 2, of depth 4 must have length >= 8, etc.
|
||||
* BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of depth n is "balanced",
|
||||
* i.e flat enough, if its length is at least Fn+2, e.g. a "balanced" {@link RopeByteString} of
|
||||
* depth 1 must have length at least 2, of depth 4 must have length >= 8, etc.
|
||||
*
|
||||
* <p>There's nothing special about using the Fibonacci numbers for this, but
|
||||
* they are a reasonable sequence for encapsulating the idea that we are OK
|
||||
* with longer strings being encoded in deeper binary trees.
|
||||
* <p>There's nothing special about using the Fibonacci numbers for this, but they are a
|
||||
* reasonable sequence for encapsulating the idea that we are OK with longer strings being encoded
|
||||
* in deeper binary trees.
|
||||
*
|
||||
* <p>For 32-bit integers, this array has length 46.
|
||||
*/
|
||||
@ -121,13 +115,11 @@ final class RopeByteString extends ByteString {
|
||||
private final int treeDepth;
|
||||
|
||||
/**
|
||||
* Create a new RopeByteString, which can be thought of as a new tree node, by
|
||||
* recording references to the two given strings.
|
||||
* Create a new RopeByteString, which can be thought of as a new tree node, by recording
|
||||
* references to the two given strings.
|
||||
*
|
||||
* @param left string on the left of this node, should have {@code size() >
|
||||
* 0}
|
||||
* @param right string on the right of this node, should have {@code size() >
|
||||
* 0}
|
||||
* @param left string on the left of this node, should have {@code size() > 0}
|
||||
* @param right string on the right of this node, should have {@code size() > 0}
|
||||
*/
|
||||
private RopeByteString(ByteString left, ByteString right) {
|
||||
this.left = left;
|
||||
@ -138,17 +130,15 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate the given strings while performing various optimizations to
|
||||
* slow the growth rate of tree depth and tree node count. The result is
|
||||
* either a {@link com.google.protobuf.ByteString.LeafByteString} or a
|
||||
* {@link RopeByteString} depending on which optimizations, if any, were
|
||||
* applied.
|
||||
* Concatenate the given strings while performing various optimizations to slow the growth rate of
|
||||
* tree depth and tree node count. The result is either a {@link
|
||||
* com.google.protobuf.ByteString.LeafByteString} or a {@link RopeByteString} depending on which
|
||||
* optimizations, if any, were applied.
|
||||
*
|
||||
* <p>Small pieces of length less than {@link
|
||||
* ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
|
||||
* BAP95. Large pieces are referenced without copy.
|
||||
* <p>Small pieces of length less than {@link ByteString#CONCATENATE_BY_COPY_SIZE} may be copied
|
||||
* by value here, as in BAP95. Large pieces are referenced without copy.
|
||||
*
|
||||
* @param left string on the left
|
||||
* @param left string on the left
|
||||
* @param right string on the right
|
||||
* @return concatenation representing the same sequence as the given strings
|
||||
*/
|
||||
@ -208,31 +198,29 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates two strings by copying data values. This is called in a few
|
||||
* cases in order to reduce the growth of the number of tree nodes.
|
||||
* Concatenates two strings by copying data values. This is called in a few cases in order to
|
||||
* reduce the growth of the number of tree nodes.
|
||||
*
|
||||
* @param left string on the left
|
||||
* @param left string on the left
|
||||
* @param right string on the right
|
||||
* @return string formed by copying data bytes
|
||||
*/
|
||||
private static ByteString concatenateBytes(ByteString left,
|
||||
ByteString right) {
|
||||
private static ByteString concatenateBytes(ByteString left, ByteString right) {
|
||||
int leftSize = left.size();
|
||||
int rightSize = right.size();
|
||||
byte[] bytes = new byte[leftSize + rightSize];
|
||||
left.copyTo(bytes, 0, 0, leftSize);
|
||||
right.copyTo(bytes, 0, leftSize, rightSize);
|
||||
return ByteString.wrap(bytes); // Constructor wraps bytes
|
||||
return ByteString.wrap(bytes); // Constructor wraps bytes
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RopeByteString for testing only while bypassing all the
|
||||
* defenses of {@link #concatenate(ByteString, ByteString)}. This allows
|
||||
* testing trees of specific structure. We are also able to insert empty
|
||||
* leaves, though these are dis-allowed, so that we can make sure the
|
||||
* Create a new RopeByteString for testing only while bypassing all the defenses of {@link
|
||||
* #concatenate(ByteString, ByteString)}. This allows testing trees of specific structure. We are
|
||||
* also able to insert empty leaves, though these are dis-allowed, so that we can make sure the
|
||||
* implementation can withstand their presence.
|
||||
*
|
||||
* @param left string on the left of this node
|
||||
* @param left string on the left of this node
|
||||
* @param right string on the right of this node
|
||||
* @return an unsafe instance for testing only
|
||||
*/
|
||||
@ -241,9 +229,8 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the byte at the given index.
|
||||
* Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility
|
||||
* reasons although it would more properly be {@link
|
||||
* Gets the byte at the given index. Throws {@link ArrayIndexOutOfBoundsException} for
|
||||
* backwards-compatibility reasons although it would more properly be {@link
|
||||
* IndexOutOfBoundsException}.
|
||||
*
|
||||
* @param index index of byte
|
||||
@ -276,10 +263,9 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the tree is balanced according to BAP95, which means the tree
|
||||
* is flat-enough with respect to the bounds. Note that this definition of
|
||||
* balanced is one where sub-trees of balanced trees are not necessarily
|
||||
* balanced.
|
||||
* Determines if the tree is balanced according to BAP95, which means the tree is flat-enough with
|
||||
* respect to the bounds. Note that this definition of balanced is one where sub-trees of balanced
|
||||
* trees are not necessarily balanced.
|
||||
*
|
||||
* @return true if the tree is balanced
|
||||
*/
|
||||
@ -289,17 +275,16 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a substring of this one. This involves recursive descent along the
|
||||
* left and right edges of the substring, and referencing any wholly contained
|
||||
* segments in between. Any leaf nodes entirely uninvolved in the substring
|
||||
* will not be referenced by the substring.
|
||||
* Takes a substring of this one. This involves recursive descent along the left and right edges
|
||||
* of the substring, and referencing any wholly contained segments in between. Any leaf nodes
|
||||
* entirely uninvolved in the substring will not be referenced by the substring.
|
||||
*
|
||||
* <p>Substrings of {@code length < 2} should result in at most a single
|
||||
* recursive call chain, terminating at a leaf node. Thus the result will be a
|
||||
* {@link com.google.protobuf.ByteString.LeafByteString}.
|
||||
* <p>Substrings of {@code length < 2} should result in at most a single recursive call chain,
|
||||
* terminating at a leaf node. Thus the result will be a {@link
|
||||
* com.google.protobuf.ByteString.LeafByteString}.
|
||||
*
|
||||
* @param beginIndex start at this index
|
||||
* @param endIndex the last character is the one before this index
|
||||
* @param endIndex the last character is the one before this index
|
||||
* @return substring leaf node or tree
|
||||
*/
|
||||
@Override
|
||||
@ -340,18 +325,16 @@ final class RopeByteString extends ByteString {
|
||||
// ByteString -> byte[]
|
||||
|
||||
@Override
|
||||
protected void copyToInternal(byte[] target, int sourceOffset,
|
||||
int targetOffset, int numberToCopy) {
|
||||
if (sourceOffset + numberToCopy <= leftLength) {
|
||||
protected void copyToInternal(
|
||||
byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
|
||||
if (sourceOffset + numberToCopy <= leftLength) {
|
||||
left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
|
||||
} else if (sourceOffset >= leftLength) {
|
||||
right.copyToInternal(target, sourceOffset - leftLength, targetOffset,
|
||||
numberToCopy);
|
||||
right.copyToInternal(target, sourceOffset - leftLength, targetOffset, numberToCopy);
|
||||
} else {
|
||||
int leftLength = this.leftLength - sourceOffset;
|
||||
left.copyToInternal(target, sourceOffset, targetOffset, leftLength);
|
||||
right.copyToInternal(target, 0, targetOffset + leftLength,
|
||||
numberToCopy - leftLength);
|
||||
right.copyToInternal(target, 0, targetOffset + leftLength, numberToCopy - leftLength);
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,8 +370,7 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeToInternal(OutputStream out, int sourceOffset,
|
||||
int numberToWrite) throws IOException {
|
||||
void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) throws IOException {
|
||||
if (sourceOffset + numberToWrite <= leftLength) {
|
||||
left.writeToInternal(out, sourceOffset, numberToWrite);
|
||||
} else if (sourceOffset >= leftLength) {
|
||||
@ -471,13 +453,11 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this string is equal to another of the same length by
|
||||
* iterating over the leaf nodes. On each step of the iteration, the
|
||||
* overlapping segments of the leaves are compared.
|
||||
* Determines if this string is equal to another of the same length by iterating over the leaf
|
||||
* nodes. On each step of the iteration, the overlapping segments of the leaves are compared.
|
||||
*
|
||||
* @param other string of the same length as this one
|
||||
* @return true if the values of this string equals the value of the given
|
||||
* one
|
||||
* @return true if the values of this string equals the value of the given one
|
||||
*/
|
||||
private boolean equalsFragments(ByteString other) {
|
||||
int thisOffset = 0;
|
||||
@ -495,9 +475,10 @@ final class RopeByteString extends ByteString {
|
||||
int bytesToCompare = Math.min(thisRemaining, thatRemaining);
|
||||
|
||||
// At least one of the offsets will be zero
|
||||
boolean stillEqual = (thisOffset == 0)
|
||||
? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
|
||||
: thatString.equalsRange(thisString, thisOffset, bytesToCompare);
|
||||
boolean stillEqual =
|
||||
(thisOffset == 0)
|
||||
? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
|
||||
: thatString.equalsRange(thisString, thisOffset, bytesToCompare);
|
||||
if (!stillEqual) {
|
||||
return false;
|
||||
}
|
||||
@ -553,14 +534,13 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class implements the balancing algorithm of BAP95. In the paper the
|
||||
* authors use an array to keep track of pieces, while here we use a stack.
|
||||
* The tree is balanced by traversing subtrees in left to right order, and the
|
||||
* stack always contains the part of the string we've traversed so far.
|
||||
* This class implements the balancing algorithm of BAP95. In the paper the authors use an array
|
||||
* to keep track of pieces, while here we use a stack. The tree is balanced by traversing subtrees
|
||||
* in left to right order, and the stack always contains the part of the string we've traversed so
|
||||
* far.
|
||||
*
|
||||
* <p>One surprising aspect of the algorithm is the result of balancing is not
|
||||
* necessarily balanced, though it is nearly balanced. For details, see
|
||||
* BAP95.
|
||||
* <p>One surprising aspect of the algorithm is the result of balancing is not necessarily
|
||||
* balanced, though it is nearly balanced. For details, see BAP95.
|
||||
*/
|
||||
private static class Balancer {
|
||||
// Stack containing the part of the string, starting from the left, that
|
||||
@ -596,21 +576,18 @@ final class RopeByteString extends ByteString {
|
||||
doBalance(rbs.right);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Has a new type of ByteString been created? Found " +
|
||||
root.getClass());
|
||||
"Has a new type of ByteString been created? Found " + root.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a string on the balance stack (BAP95). BAP95 uses an array and
|
||||
* calls the elements in the array 'bins'. We instead use a stack, so the
|
||||
* 'bins' of lengths are represented by differences between the elements of
|
||||
* minLengthByDepth.
|
||||
* Push a string on the balance stack (BAP95). BAP95 uses an array and calls the elements in the
|
||||
* array 'bins'. We instead use a stack, so the 'bins' of lengths are represented by differences
|
||||
* between the elements of minLengthByDepth.
|
||||
*
|
||||
* <p>If the length bin for our string, and all shorter length bins, are
|
||||
* empty, we just push it on the stack. Otherwise, we need to start
|
||||
* concatenating, putting the given string in the "middle" and continuing
|
||||
* until we land in an empty length bin that matches the length of our
|
||||
* <p>If the length bin for our string, and all shorter length bins, are empty, we just push it
|
||||
* on the stack. Otherwise, we need to start concatenating, putting the given string in the
|
||||
* "middle" and continuing until we land in an empty length bin that matches the length of our
|
||||
* concatenation.
|
||||
*
|
||||
* @param byteString string to place on the balance stack
|
||||
@ -630,8 +607,7 @@ final class RopeByteString extends ByteString {
|
||||
|
||||
// Concatenate the subtrees of shorter length
|
||||
ByteString newTree = prefixesStack.pop();
|
||||
while (!prefixesStack.isEmpty()
|
||||
&& prefixesStack.peek().size() < binStart) {
|
||||
while (!prefixesStack.isEmpty() && prefixesStack.peek().size() < binStart) {
|
||||
ByteString left = prefixesStack.pop();
|
||||
newTree = new RopeByteString(left, newTree);
|
||||
}
|
||||
@ -668,18 +644,15 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a continuable tree traversal, which keeps the state
|
||||
* information which would exist on the stack in a recursive traversal instead
|
||||
* on a stack of "Bread Crumbs". The maximum depth of the stack in this
|
||||
* iterator is the same as the depth of the tree being traversed.
|
||||
* This class is a continuable tree traversal, which keeps the state information which would exist
|
||||
* on the stack in a recursive traversal instead on a stack of "Bread Crumbs". The maximum depth
|
||||
* of the stack in this iterator is the same as the depth of the tree being traversed.
|
||||
*
|
||||
* <p>This iterator is used to implement
|
||||
* {@link RopeByteString#equalsFragments(ByteString)}.
|
||||
* <p>This iterator is used to implement {@link RopeByteString#equalsFragments(ByteString)}.
|
||||
*/
|
||||
private static class PieceIterator implements Iterator<LeafByteString> {
|
||||
|
||||
private final Stack<RopeByteString> breadCrumbs =
|
||||
new Stack<RopeByteString>();
|
||||
private final Stack<RopeByteString> breadCrumbs = new Stack<RopeByteString>();
|
||||
private LeafByteString next;
|
||||
|
||||
private PieceIterator(ByteString root) {
|
||||
@ -717,8 +690,7 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next item and advances one
|
||||
* {@link com.google.protobuf.ByteString.LeafByteString}.
|
||||
* Returns the next item and advances one {@link com.google.protobuf.ByteString.LeafByteString}.
|
||||
*
|
||||
* @return next non-empty LeafByteString or {@code null}
|
||||
*/
|
||||
@ -748,14 +720,10 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
|
||||
throw new InvalidObjectException(
|
||||
"RopeByteStream instances are not to be serialized directly");
|
||||
throw new InvalidObjectException("RopeByteStream instances are not to be serialized directly");
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is the {@link RopeByteString} equivalent for
|
||||
* {@link ByteArrayInputStream}.
|
||||
*/
|
||||
/** This class is the {@link RopeByteString} equivalent for {@link ByteArrayInputStream}. */
|
||||
private class RopeInputStream extends InputStream {
|
||||
// Iterates through the pieces of the rope
|
||||
private PieceIterator pieceIterator;
|
||||
@ -775,7 +743,7 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int offset, int length) {
|
||||
public int read(byte[] b, int offset, int length) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (offset < 0 || length < 0 || length > b.length - offset) {
|
||||
@ -795,24 +763,23 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation of read and skip. If b != null, then read the
|
||||
* next {@code length} bytes into the buffer {@code b} at
|
||||
* offset {@code offset}. If b == null, then skip the next {@code length}
|
||||
* bytes.
|
||||
* <p>
|
||||
* This method assumes that all error checking has already happened.
|
||||
* <p>
|
||||
* Returns the actual number of bytes read or skipped.
|
||||
* Internal implementation of read and skip. If b != null, then read the next {@code length}
|
||||
* bytes into the buffer {@code b} at offset {@code offset}. If b == null, then skip the next
|
||||
* {@code length} bytes.
|
||||
*
|
||||
* <p>This method assumes that all error checking has already happened.
|
||||
*
|
||||
* <p>Returns the actual number of bytes read or skipped.
|
||||
*/
|
||||
private int readSkipInternal(byte b[], int offset, int length) {
|
||||
private int readSkipInternal(byte[] b, int offset, int length) {
|
||||
int bytesRemaining = length;
|
||||
while (bytesRemaining > 0) {
|
||||
advanceIfCurrentPieceFullyRead();
|
||||
if (currentPiece == null) {
|
||||
if (bytesRemaining == length) {
|
||||
// We didn't manage to read anything
|
||||
return -1;
|
||||
}
|
||||
// We didn't manage to read anything
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// Copy the bytes from this piece.
|
||||
@ -826,7 +793,7 @@ final class RopeByteString extends ByteString {
|
||||
bytesRemaining -= count;
|
||||
}
|
||||
}
|
||||
// Return the number of bytes read.
|
||||
// Return the number of bytes read.
|
||||
return length - bytesRemaining;
|
||||
}
|
||||
|
||||
@ -874,9 +841,8 @@ final class RopeByteString extends ByteString {
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips to the next piece if we have read all the data in the current
|
||||
* piece. Sets currentPiece to null if we have reached the end of the
|
||||
* input.
|
||||
* Skips to the next piece if we have read all the data in the current piece. Sets currentPiece
|
||||
* to null if we have reached the end of the input.
|
||||
*/
|
||||
private void advanceIfCurrentPieceFullyRead() {
|
||||
if (currentPiece != null && currentPieceIndex == currentPieceSize) {
|
||||
|
@ -31,14 +31,13 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Interface for an RPC callback, normally called when an RPC completes.
|
||||
* {@code ParameterType} is normally the method's response message type.
|
||||
* Interface for an RPC callback, normally called when an RPC completes. {@code ParameterType} is
|
||||
* normally the method's response message type.
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build on this, but should
|
||||
* instead provide code generator plugins which generate code specific to the particular RPC
|
||||
* implementation. This way the generated code can be more appropriate for the implementation in use
|
||||
* and can avoid unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
|
@ -31,11 +31,10 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
|
||||
* communication line to a {@link Service} which can be used to call that
|
||||
* {@link Service}'s methods. The {@link Service} may be running on another
|
||||
* machine. Normally, you should not call an {@code RpcChannel} directly, but
|
||||
* instead construct a stub {@link Service} wrapping it. Example:
|
||||
* Abstract interface for an RPC channel. An {@code RpcChannel} represents a communication line to a
|
||||
* {@link Service} which can be used to call that {@link Service}'s methods. The {@link Service} may
|
||||
* be running on another machine. Normally, you should not call an {@code RpcChannel} directly, but
|
||||
* instead construct a stub {@link Service} wrapping it. Example:
|
||||
*
|
||||
* <pre>
|
||||
* RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
|
||||
@ -44,28 +43,26 @@ package com.google.protobuf;
|
||||
* service.myMethod(controller, request, callback);
|
||||
* </pre>
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build on this, but should
|
||||
* instead provide code generator plugins which generate code specific to the particular RPC
|
||||
* implementation. This way the generated code can be more appropriate for the implementation in use
|
||||
* and can avoid unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface RpcChannel {
|
||||
/**
|
||||
* Call the given method of the remote service. This method is similar to
|
||||
* {@code Service.callMethod()} with one important difference: the caller
|
||||
* decides the types of the {@code Message} objects, not the callee. The
|
||||
* request may be of any type as long as
|
||||
* {@code request.getDescriptor() == method.getInputType()}.
|
||||
* The response passed to the callback will be of the same type as
|
||||
* {@code responsePrototype} (which must have
|
||||
* {@code getDescriptor() == method.getOutputType()}).
|
||||
* Call the given method of the remote service. This method is similar to {@code
|
||||
* Service.callMethod()} with one important difference: the caller decides the types of the {@code
|
||||
* Message} objects, not the callee. The request may be of any type as long as {@code
|
||||
* request.getDescriptor() == method.getInputType()}. The response passed to the callback will be
|
||||
* of the same type as {@code responsePrototype} (which must have {@code getDescriptor() ==
|
||||
* method.getOutputType()}).
|
||||
*/
|
||||
void callMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype,
|
||||
RpcCallback<Message> done);
|
||||
void callMethod(
|
||||
Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype,
|
||||
RpcCallback<Message> done);
|
||||
}
|
||||
|
@ -31,20 +31,18 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>An {@code RpcController} mediates a single method call. The primary
|
||||
* purpose of the controller is to provide a way to manipulate settings
|
||||
* specific to the RPC implementation and to find out about RPC-level errors.
|
||||
* An {@code RpcController} mediates a single method call. The primary purpose of the controller is
|
||||
* to provide a way to manipulate settings specific to the RPC implementation and to find out about
|
||||
* RPC-level errors.
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build on this, but should
|
||||
* instead provide code generator plugins which generate code specific to the particular RPC
|
||||
* implementation. This way the generated code can be more appropriate for the implementation in use
|
||||
* and can avoid unnecessary layers of indirection.
|
||||
*
|
||||
* <p>The methods provided by the {@code RpcController} interface are intended
|
||||
* to be a "least common denominator" set of features which we expect all
|
||||
* implementations to support. Specific implementations may provide more
|
||||
* advanced features (e.g. deadline propagation).
|
||||
* <p>The methods provided by the {@code RpcController} interface are intended to be a "least common
|
||||
* denominator" set of features which we expect all implementations to support. Specific
|
||||
* implementations may provide more advanced features (e.g. deadline propagation).
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -54,31 +52,25 @@ public interface RpcController {
|
||||
// are undefined on the server side (may throw RuntimeExceptions).
|
||||
|
||||
/**
|
||||
* Resets the RpcController to its initial state so that it may be reused in
|
||||
* a new call. This can be called from the client side only. It must not
|
||||
* be called while an RPC is in progress.
|
||||
* Resets the RpcController to its initial state so that it may be reused in a new call. This can
|
||||
* be called from the client side only. It must not be called while an RPC is in progress.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* After a call has finished, returns true if the call failed. The possible
|
||||
* reasons for failure depend on the RPC implementation. {@code failed()}
|
||||
* most only be called on the client side, and must not be called before a
|
||||
* call has finished.
|
||||
* After a call has finished, returns true if the call failed. The possible reasons for failure
|
||||
* depend on the RPC implementation. {@code failed()} most only be called on the client side, and
|
||||
* must not be called before a call has finished.
|
||||
*/
|
||||
boolean failed();
|
||||
|
||||
/**
|
||||
* If {@code failed()} is {@code true}, returns a human-readable description
|
||||
* of the error.
|
||||
*/
|
||||
/** If {@code failed()} is {@code true}, returns a human-readable description of the error. */
|
||||
String errorText();
|
||||
|
||||
/**
|
||||
* Advises the RPC system that the caller desires that the RPC call be
|
||||
* canceled. The RPC system may cancel it immediately, may wait awhile and
|
||||
* then cancel it, or may not even cancel the call at all. If the call is
|
||||
* canceled, the "done" callback will still be called and the RpcController
|
||||
* Advises the RPC system that the caller desires that the RPC call be canceled. The RPC system
|
||||
* may cancel it immediately, may wait awhile and then cancel it, or may not even cancel the call
|
||||
* at all. If the call is canceled, the "done" callback will still be called and the RpcController
|
||||
* will indicate that the call failed at that time.
|
||||
*/
|
||||
void startCancel();
|
||||
@ -88,31 +80,29 @@ public interface RpcController {
|
||||
// are undefined on the client side (may throw RuntimeExceptions).
|
||||
|
||||
/**
|
||||
* Causes {@code failed()} to return true on the client side. {@code reason}
|
||||
* will be incorporated into the message returned by {@code errorText()}.
|
||||
* If you find you need to return machine-readable information about
|
||||
* failures, you should incorporate it into your response protocol buffer
|
||||
* and should NOT call {@code setFailed()}.
|
||||
* Causes {@code failed()} to return true on the client side. {@code reason} will be incorporated
|
||||
* into the message returned by {@code errorText()}. If you find you need to return
|
||||
* machine-readable information about failures, you should incorporate it into your response
|
||||
* protocol buffer and should NOT call {@code setFailed()}.
|
||||
*/
|
||||
void setFailed(String reason);
|
||||
|
||||
/**
|
||||
* If {@code true}, indicates that the client canceled the RPC, so the server
|
||||
* may as well give up on replying to it. This method must be called on the
|
||||
* server side only. The server should still call the final "done" callback.
|
||||
* If {@code true}, indicates that the client canceled the RPC, so the server may as well give up
|
||||
* on replying to it. This method must be called on the server side only. The server should still
|
||||
* call the final "done" callback.
|
||||
*/
|
||||
boolean isCanceled();
|
||||
|
||||
/**
|
||||
* Asks that the given callback be called when the RPC is canceled. The
|
||||
* parameter passed to the callback will always be {@code null}. The
|
||||
* callback will always be called exactly once. If the RPC completes without
|
||||
* being canceled, the callback will be called after completion. If the RPC
|
||||
* has already been canceled when NotifyOnCancel() is called, the callback
|
||||
* will be called immediately.
|
||||
* Asks that the given callback be called when the RPC is canceled. The parameter passed to the
|
||||
* callback will always be {@code null}. The callback will always be called exactly once. If the
|
||||
* RPC completes without being canceled, the callback will be called after completion. If the RPC
|
||||
* has already been canceled when NotifyOnCancel() is called, the callback will be called
|
||||
* immediately.
|
||||
*
|
||||
* <p>{@code notifyOnCancel()} must be called no more than once per request.
|
||||
* It must be called on the server side only.
|
||||
* <p>{@code notifyOnCancel()} must be called no more than once per request. It must be called on
|
||||
* the server side only.
|
||||
*/
|
||||
void notifyOnCancel(RpcCallback<Object> callback);
|
||||
}
|
||||
|
@ -39,14 +39,13 @@ public final class RpcUtil {
|
||||
private RpcUtil() {}
|
||||
|
||||
/**
|
||||
* Take an {@code RpcCallback<Message>} and convert it to an
|
||||
* {@code RpcCallback} accepting a specific message type. This is always
|
||||
* type-safe (parameter type contravariance).
|
||||
* Take an {@code RpcCallback<Message>} and convert it to an {@code RpcCallback} accepting a
|
||||
* specific message type. This is always type-safe (parameter type contravariance).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <Type extends Message> RpcCallback<Type>
|
||||
specializeCallback(final RpcCallback<Message> originalCallback) {
|
||||
return (RpcCallback<Type>)originalCallback;
|
||||
public static <Type extends Message> RpcCallback<Type> specializeCallback(
|
||||
final RpcCallback<Message> originalCallback) {
|
||||
return (RpcCallback<Type>) originalCallback;
|
||||
// The above cast works, but only due to technical details of the Java
|
||||
// implementation. A more theoretically correct -- but less efficient --
|
||||
// implementation would be as follows:
|
||||
@ -58,15 +57,13 @@ public final class RpcUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an {@code RpcCallback} accepting a specific message type and convert
|
||||
* it to an {@code RpcCallback<Message>}. The generalized callback will
|
||||
* accept any message object which has the same descriptor, and will convert
|
||||
* it to the correct class before calling the original callback. However,
|
||||
* if the generalized callback is given a message with a different descriptor,
|
||||
* an exception will be thrown.
|
||||
* Take an {@code RpcCallback} accepting a specific message type and convert it to an {@code
|
||||
* RpcCallback<Message>}. The generalized callback will accept any message object which has the
|
||||
* same descriptor, and will convert it to the correct class before calling the original callback.
|
||||
* However, if the generalized callback is given a message with a different descriptor, an
|
||||
* exception will be thrown.
|
||||
*/
|
||||
public static <Type extends Message>
|
||||
RpcCallback<Message> generalizeCallback(
|
||||
public static <Type extends Message> RpcCallback<Message> generalizeCallback(
|
||||
final RpcCallback<Type> originalCallback,
|
||||
final Class<Type> originalClass,
|
||||
final Type defaultInstance) {
|
||||
@ -85,25 +82,21 @@ public final class RpcUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new message of type "Type" which is a copy of "source". "source"
|
||||
* must have the same descriptor but may be a different class (e.g.
|
||||
* DynamicMessage).
|
||||
* Creates a new message of type "Type" which is a copy of "source". "source" must have the same
|
||||
* descriptor but may be a different class (e.g. DynamicMessage).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <Type extends Message> Type copyAsType(
|
||||
final Type typeDefaultInstance, final Message source) {
|
||||
return (Type) typeDefaultInstance
|
||||
.newBuilderForType().mergeFrom(source).build();
|
||||
return (Type) typeDefaultInstance.newBuilderForType().mergeFrom(source).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a callback which can only be called once. This may be useful for
|
||||
* security, when passing a callback to untrusted code: most callbacks do
|
||||
* not expect to be called more than once, so doing so may expose bugs if it
|
||||
* is not prevented.
|
||||
* Creates a callback which can only be called once. This may be useful for security, when passing
|
||||
* a callback to untrusted code: most callbacks do not expect to be called more than once, so
|
||||
* doing so may expose bugs if it is not prevented.
|
||||
*/
|
||||
public static <ParameterType>
|
||||
RpcCallback<ParameterType> newOneTimeCallback(
|
||||
public static <ParameterType> RpcCallback<ParameterType> newOneTimeCallback(
|
||||
final RpcCallback<ParameterType> originalCallback) {
|
||||
return new RpcCallback<ParameterType>() {
|
||||
private boolean alreadyCalled = false;
|
||||
@ -122,15 +115,12 @@ public final class RpcUtil {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a one-time callback is called more than once.
|
||||
*/
|
||||
/** Exception thrown when a one-time callback is called more than once. */
|
||||
public static final class AlreadyCalledException extends RuntimeException {
|
||||
private static final long serialVersionUID = 5469741279507848266L;
|
||||
|
||||
public AlreadyCalledException() {
|
||||
super("This RpcCallback was already called and cannot be called " +
|
||||
"multiple times.");
|
||||
super("This RpcCallback was already called and cannot be called multiple times.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,70 +31,63 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Abstract base interface for protocol-buffer-based RPC services. Services
|
||||
* themselves are abstract classes (implemented either by servers or as
|
||||
* stubs), but they subclass this base interface. The methods of this
|
||||
* interface can be used to call the methods of the service without knowing
|
||||
* its exact type at compile time (analogous to the Message interface).
|
||||
* Abstract base interface for protocol-buffer-based RPC services. Services themselves are abstract
|
||||
* classes (implemented either by servers or as stubs), but they subclass this base interface. The
|
||||
* methods of this interface can be used to call the methods of the service without knowing its
|
||||
* exact type at compile time (analogous to the Message interface).
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build on this, but should
|
||||
* instead provide code generator plugins which generate code specific to the particular RPC
|
||||
* implementation. This way the generated code can be more appropriate for the implementation in use
|
||||
* and can avoid unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface Service {
|
||||
/**
|
||||
* Get the {@code ServiceDescriptor} describing this service and its methods.
|
||||
*/
|
||||
/** Get the {@code ServiceDescriptor} describing this service and its methods. */
|
||||
Descriptors.ServiceDescriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* <p>Call a method of the service specified by MethodDescriptor. This is
|
||||
* normally implemented as a simple {@code switch()} that calls the standard
|
||||
* definitions of the service's methods.
|
||||
* Call a method of the service specified by MethodDescriptor. This is normally implemented as a
|
||||
* simple {@code switch()} that calls the standard definitions of the service's methods.
|
||||
*
|
||||
* <p>Preconditions:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code method.getService() == getDescriptorForType()}
|
||||
* <li>{@code request} is of the exact same class as the object returned by
|
||||
* {@code getRequestPrototype(method)}.
|
||||
* <li>{@code controller} is of the correct type for the RPC implementation
|
||||
* being used by this Service. For stubs, the "correct type" depends
|
||||
* on the RpcChannel which the stub is using. Server-side Service
|
||||
* implementations are expected to accept whatever type of
|
||||
* {@code RpcController} the server-side RPC implementation uses.
|
||||
* <li>{@code request} is of the exact same class as the object returned by {@code
|
||||
* getRequestPrototype(method)}.
|
||||
* <li>{@code controller} is of the correct type for the RPC implementation being used by this
|
||||
* Service. For stubs, the "correct type" depends on the RpcChannel which the stub is using.
|
||||
* Server-side Service implementations are expected to accept whatever type of {@code
|
||||
* RpcController} the server-side RPC implementation uses.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Postconditions:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code done} will be called when the method is complete. This may be
|
||||
* before {@code callMethod()} returns or it may be at some point in
|
||||
* the future.
|
||||
* <li>The parameter to {@code done} is the response. It must be of the
|
||||
* exact same type as would be returned by
|
||||
* {@code getResponsePrototype(method)}.
|
||||
* <li>If the RPC failed, the parameter to {@code done} will be
|
||||
* {@code null}. Further details about the failure can be found by
|
||||
* querying {@code controller}.
|
||||
* <li>{@code done} will be called when the method is complete. This may be before {@code
|
||||
* callMethod()} returns or it may be at some point in the future.
|
||||
* <li>The parameter to {@code done} is the response. It must be of the exact same type as would
|
||||
* be returned by {@code getResponsePrototype(method)}.
|
||||
* <li>If the RPC failed, the parameter to {@code done} will be {@code null}. Further details
|
||||
* about the failure can be found by querying {@code controller}.
|
||||
* </ul>
|
||||
*/
|
||||
void callMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
RpcCallback<Message> done);
|
||||
void callMethod(
|
||||
Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
RpcCallback<Message> done);
|
||||
|
||||
/**
|
||||
* <p>{@code callMethod()} requires that the request passed in is of a
|
||||
* particular subclass of {@code Message}. {@code getRequestPrototype()}
|
||||
* gets the default instances of this type for a given method. You can then
|
||||
* call {@code Message.newBuilderForType()} on this instance to
|
||||
* construct a builder to build an object which you can then pass to
|
||||
* {@code callMethod()}.
|
||||
* {@code callMethod()} requires that the request passed in is of a particular subclass of {@code
|
||||
* Message}. {@code getRequestPrototype()} gets the default instances of this type for a given
|
||||
* method. You can then call {@code Message.newBuilderForType()} on this instance to construct a
|
||||
* builder to build an object which you can then pass to {@code callMethod()}.
|
||||
*
|
||||
* <p>Example:
|
||||
*
|
||||
* <pre>
|
||||
* MethodDescriptor method =
|
||||
* service.getDescriptorForType().findMethodByName("Foo");
|
||||
@ -107,11 +100,10 @@ public interface Service {
|
||||
Message getRequestPrototype(Descriptors.MethodDescriptor method);
|
||||
|
||||
/**
|
||||
* Like {@code getRequestPrototype()}, but gets a prototype of the response
|
||||
* message. {@code getResponsePrototype()} is generally not needed because
|
||||
* the {@code Service} implementation constructs the response message itself,
|
||||
* but it may be useful in some cases to know ahead of time what type of
|
||||
* object will be returned.
|
||||
* Like {@code getRequestPrototype()}, but gets a prototype of the response message. {@code
|
||||
* getResponsePrototype()} is generally not needed because the {@code Service} implementation
|
||||
* constructs the response message itself, but it may be useful in some cases to know ahead of
|
||||
* time what type of object will be returned.
|
||||
*/
|
||||
Message getResponsePrototype(Descriptors.MethodDescriptor method);
|
||||
}
|
||||
|
@ -33,35 +33,29 @@ package com.google.protobuf;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
/**
|
||||
* {@code SingleFieldBuilder} implements a structure that a protocol
|
||||
* message uses to hold a single field of another protocol message. It supports
|
||||
* the classical use case of setting an immutable {@link Message} as the value
|
||||
* of the field and is highly optimized around this.
|
||||
* {@code SingleFieldBuilder} implements a structure that a protocol message uses to hold a single
|
||||
* field of another protocol message. It supports the classical use case of setting an immutable
|
||||
* {@link Message} as the value of the field and is highly optimized around this.
|
||||
*
|
||||
* <p>It also supports the additional use case of setting a {@link Message.Builder} as the field and
|
||||
* deferring conversion of that {@code Builder} to an immutable {@code Message}. In this way, it's
|
||||
* possible to maintain a tree of {@code Builder}'s that acts as a fully read/write data structure.
|
||||
* <br>
|
||||
* It also supports the additional use case of setting a {@link Message.Builder}
|
||||
* as the field and deferring conversion of that {@code Builder}
|
||||
* to an immutable {@code Message}. In this way, it's possible to maintain
|
||||
* a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure.
|
||||
* <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree
|
||||
* to messages when build is called on the root or when any method is called
|
||||
* that desires a Message instead of a Builder. In terms of the implementation,
|
||||
* the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
|
||||
* classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its
|
||||
* descendants.
|
||||
* Logically, one can think of a tree of builders as converting the entire tree to messages when
|
||||
* build is called on the root or when any method is called that desires a Message instead of a
|
||||
* Builder. In terms of the implementation, the {@code SingleFieldBuilder} and {@code
|
||||
* RepeatedFieldBuilder} classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its descendants.
|
||||
*
|
||||
* @param <MType> the type of message for the field
|
||||
* @param <BType> the type of builder for the field
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class SingleFieldBuilder
|
||||
<MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
public class SingleFieldBuilder<
|
||||
MType extends GeneratedMessage,
|
||||
BType extends GeneratedMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
implements GeneratedMessage.BuilderParent {
|
||||
|
||||
// Parent to send changes to.
|
||||
@ -82,10 +76,7 @@ public class SingleFieldBuilder
|
||||
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
|
||||
private boolean isClean;
|
||||
|
||||
public SingleFieldBuilder(
|
||||
MType message,
|
||||
GeneratedMessage.BuilderParent parent,
|
||||
boolean isClean) {
|
||||
public SingleFieldBuilder(MType message, GeneratedMessage.BuilderParent parent, boolean isClean) {
|
||||
this.message = checkNotNull(message);
|
||||
this.parent = parent;
|
||||
this.isClean = isClean;
|
||||
@ -97,10 +88,9 @@ public class SingleFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message for the field. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it. If no message has
|
||||
* been set, returns the default instance of the message.
|
||||
* Get the message for the field. If the message is currently stored as a {@code Builder}, it is
|
||||
* converted to a {@code Message} by calling {@link Message.Builder#buildPartial} on it. If no
|
||||
* message has been set, returns the default instance of the message.
|
||||
*
|
||||
* @return the message for the field
|
||||
*/
|
||||
@ -126,8 +116,8 @@ public class SingleFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a builder for the field. If no builder has been created yet, a
|
||||
* builder is created on demand by calling {@link Message#toBuilder}.
|
||||
* Gets a builder for the field. If no builder has been created yet, a builder is created on
|
||||
* demand by calling {@link Message#toBuilder}.
|
||||
*
|
||||
* @return The builder for the field
|
||||
*/
|
||||
@ -146,28 +136,27 @@ public class SingleFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class interface for the field. This may either be a builder
|
||||
* or a message. It will return whatever is more efficient.
|
||||
* Gets the base class interface for the field. This may either be a builder or a message. It will
|
||||
* return whatever is more efficient.
|
||||
*
|
||||
* @return the message or builder for the field as the base class interface
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public IType getMessageOrBuilder() {
|
||||
if (builder != null) {
|
||||
return (IType) builder;
|
||||
return (IType) builder;
|
||||
} else {
|
||||
return (IType) message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a message for the field replacing any existing value.
|
||||
* Sets a message for the field replacing any existing value.
|
||||
*
|
||||
* @param message the message to set
|
||||
* @return the builder
|
||||
*/
|
||||
public SingleFieldBuilder<MType, BType, IType> setMessage(
|
||||
MType message) {
|
||||
public SingleFieldBuilder<MType, BType, IType> setMessage(MType message) {
|
||||
this.message = checkNotNull(message);
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
@ -183,8 +172,7 @@ public class SingleFieldBuilder
|
||||
* @param value the value to merge from
|
||||
* @return the builder
|
||||
*/
|
||||
public SingleFieldBuilder<MType, BType, IType> mergeFrom(
|
||||
MType value) {
|
||||
public SingleFieldBuilder<MType, BType, IType> mergeFrom(MType value) {
|
||||
if (builder == null && message == message.getDefaultInstanceForType()) {
|
||||
message = value;
|
||||
} else {
|
||||
@ -201,9 +189,11 @@ public class SingleFieldBuilder
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SingleFieldBuilder<MType, BType, IType> clear() {
|
||||
message = (MType) (message != null ?
|
||||
message.getDefaultInstanceForType() :
|
||||
builder.getDefaultInstanceForType());
|
||||
message =
|
||||
(MType)
|
||||
(message != null
|
||||
? message.getDefaultInstanceForType()
|
||||
: builder.getDefaultInstanceForType());
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
builder = null;
|
||||
@ -213,8 +203,8 @@ public class SingleFieldBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a the builder or one of its nested children has changed
|
||||
* and any parent should be notified of its invalidation.
|
||||
* Called when a the builder or one of its nested children has changed and any parent should be
|
||||
* notified of its invalidation.
|
||||
*/
|
||||
private void onChanged() {
|
||||
// If builder is null, this is the case where onChanged is being called
|
||||
|
@ -33,35 +33,29 @@ package com.google.protobuf;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
/**
|
||||
* {@code SingleFieldBuilderV3} implements a structure that a protocol
|
||||
* message uses to hold a single field of another protocol message. It supports
|
||||
* the classical use case of setting an immutable {@link Message} as the value
|
||||
* of the field and is highly optimized around this.
|
||||
* {@code SingleFieldBuilderV3} implements a structure that a protocol message uses to hold a single
|
||||
* field of another protocol message. It supports the classical use case of setting an immutable
|
||||
* {@link Message} as the value of the field and is highly optimized around this.
|
||||
*
|
||||
* <p>It also supports the additional use case of setting a {@link Message.Builder} as the field and
|
||||
* deferring conversion of that {@code Builder} to an immutable {@code Message}. In this way, it's
|
||||
* possible to maintain a tree of {@code Builder}'s that acts as a fully read/write data structure.
|
||||
* <br>
|
||||
* It also supports the additional use case of setting a {@link Message.Builder}
|
||||
* as the field and deferring conversion of that {@code Builder}
|
||||
* to an immutable {@code Message}. In this way, it's possible to maintain
|
||||
* a tree of {@code Builder}'s that acts as a fully read/write data
|
||||
* structure.
|
||||
* <br>
|
||||
* Logically, one can think of a tree of builders as converting the entire tree
|
||||
* to messages when build is called on the root or when any method is called
|
||||
* that desires a Message instead of a Builder. In terms of the implementation,
|
||||
* the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
|
||||
* classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its
|
||||
* descendants.
|
||||
* Logically, one can think of a tree of builders as converting the entire tree to messages when
|
||||
* build is called on the root or when any method is called that desires a Message instead of a
|
||||
* Builder. In terms of the implementation, the {@code SingleFieldBuilderV3} and {@code
|
||||
* RepeatedFieldBuilderV3} classes cache messages that were created so that messages only need to be
|
||||
* created when some change occurred in its builder or a builder for one of its descendants.
|
||||
*
|
||||
* @param <MType> the type of message for the field
|
||||
* @param <BType> the type of builder for the field
|
||||
* @param <IType> the common interface for the message and the builder
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class SingleFieldBuilderV3
|
||||
<MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
public class SingleFieldBuilderV3<
|
||||
MType extends AbstractMessage,
|
||||
BType extends AbstractMessage.Builder,
|
||||
IType extends MessageOrBuilder>
|
||||
implements AbstractMessage.BuilderParent {
|
||||
|
||||
// Parent to send changes to.
|
||||
@ -82,10 +76,7 @@ public class SingleFieldBuilderV3
|
||||
// to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
|
||||
private boolean isClean;
|
||||
|
||||
public SingleFieldBuilderV3(
|
||||
MType message,
|
||||
AbstractMessage.BuilderParent parent,
|
||||
boolean isClean) {
|
||||
public SingleFieldBuilderV3(MType message, AbstractMessage.BuilderParent parent, boolean isClean) {
|
||||
this.message = checkNotNull(message);
|
||||
this.parent = parent;
|
||||
this.isClean = isClean;
|
||||
@ -97,10 +88,9 @@ public class SingleFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message for the field. If the message is currently stored
|
||||
* as a {@code Builder}, it is converted to a {@code Message} by
|
||||
* calling {@link Message.Builder#buildPartial} on it. If no message has
|
||||
* been set, returns the default instance of the message.
|
||||
* Get the message for the field. If the message is currently stored as a {@code Builder}, it is
|
||||
* converted to a {@code Message} by calling {@link Message.Builder#buildPartial} on it. If no
|
||||
* message has been set, returns the default instance of the message.
|
||||
*
|
||||
* @return the message for the field
|
||||
*/
|
||||
@ -126,8 +116,8 @@ public class SingleFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a builder for the field. If no builder has been created yet, a
|
||||
* builder is created on demand by calling {@link Message#toBuilder}.
|
||||
* Gets a builder for the field. If no builder has been created yet, a builder is created on
|
||||
* demand by calling {@link Message#toBuilder}.
|
||||
*
|
||||
* @return The builder for the field
|
||||
*/
|
||||
@ -146,28 +136,27 @@ public class SingleFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class interface for the field. This may either be a builder
|
||||
* or a message. It will return whatever is more efficient.
|
||||
* Gets the base class interface for the field. This may either be a builder or a message. It will
|
||||
* return whatever is more efficient.
|
||||
*
|
||||
* @return the message or builder for the field as the base class interface
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public IType getMessageOrBuilder() {
|
||||
if (builder != null) {
|
||||
return (IType) builder;
|
||||
return (IType) builder;
|
||||
} else {
|
||||
return (IType) message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a message for the field replacing any existing value.
|
||||
* Sets a message for the field replacing any existing value.
|
||||
*
|
||||
* @param message the message to set
|
||||
* @return the builder
|
||||
*/
|
||||
public SingleFieldBuilderV3<MType, BType, IType> setMessage(
|
||||
MType message) {
|
||||
public SingleFieldBuilderV3<MType, BType, IType> setMessage(MType message) {
|
||||
this.message = checkNotNull(message);
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
@ -183,8 +172,7 @@ public class SingleFieldBuilderV3
|
||||
* @param value the value to merge from
|
||||
* @return the builder
|
||||
*/
|
||||
public SingleFieldBuilderV3<MType, BType, IType> mergeFrom(
|
||||
MType value) {
|
||||
public SingleFieldBuilderV3<MType, BType, IType> mergeFrom(MType value) {
|
||||
if (builder == null && message == message.getDefaultInstanceForType()) {
|
||||
message = value;
|
||||
} else {
|
||||
@ -201,9 +189,11 @@ public class SingleFieldBuilderV3
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SingleFieldBuilderV3<MType, BType, IType> clear() {
|
||||
message = (MType) (message != null ?
|
||||
message.getDefaultInstanceForType() :
|
||||
builder.getDefaultInstanceForType());
|
||||
message =
|
||||
(MType)
|
||||
(message != null
|
||||
? message.getDefaultInstanceForType()
|
||||
: builder.getDefaultInstanceForType());
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
builder = null;
|
||||
@ -213,8 +203,8 @@ public class SingleFieldBuilderV3
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a the builder or one of its nested children has changed
|
||||
* and any parent should be notified of its invalidation.
|
||||
* Called when a the builder or one of its nested children has changed and any parent should be
|
||||
* notified of its invalidation.
|
||||
*/
|
||||
private void onChanged() {
|
||||
// If builder is null, this is the case where onChanged is being called
|
||||
|
@ -43,15 +43,14 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A custom map implementation from FieldDescriptor to Object optimized to
|
||||
* minimize the number of memory allocations for instances with a small number
|
||||
* of mappings. The implementation stores the first {@code k} mappings in an
|
||||
* array for a configurable value of {@code k}, allowing direct access to the
|
||||
* corresponding {@code Entry}s without the need to create an Iterator. The
|
||||
* remaining entries are stored in an overflow map. Iteration over the entries
|
||||
* in the map should be done as follows:
|
||||
* A custom map implementation from FieldDescriptor to Object optimized to minimize the number of
|
||||
* memory allocations for instances with a small number of mappings. The implementation stores the
|
||||
* first {@code k} mappings in an array for a configurable value of {@code k}, allowing direct
|
||||
* access to the corresponding {@code Entry}s without the need to create an Iterator. The remaining
|
||||
* entries are stored in an overflow map. Iteration over the entries in the map should be done as
|
||||
* follows:
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre>{@code
|
||||
* for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
|
||||
* process(fieldMap.getArrayEntryAt(i));
|
||||
* }
|
||||
@ -60,24 +59,21 @@ import java.util.TreeMap;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* The resulting iteration is in order of ascending field tag number. The
|
||||
* object returned by {@link #entrySet()} adheres to the same contract but is
|
||||
* less efficient as it necessarily involves creating an object for iteration.
|
||||
* <p>
|
||||
* The tradeoff for this memory efficiency is that the worst case running time
|
||||
* of the {@code put()} operation is {@code O(k + lg n)}, which happens when
|
||||
* entries are added in descending order. {@code k} should be chosen such that
|
||||
* it covers enough common cases without adversely affecting larger maps. In
|
||||
* practice, the worst case scenario does not happen for extensions because
|
||||
* extension fields are serialized and deserialized in order of ascending tag
|
||||
* number, but the worst case scenario can happen for DynamicMessages.
|
||||
* <p>
|
||||
* The running time for all other operations is similar to that of
|
||||
* {@code TreeMap}.
|
||||
* <p>
|
||||
* Instances are not thread-safe until {@link #makeImmutable()} is called,
|
||||
* after which any modifying operation will result in an
|
||||
* {@link UnsupportedOperationException}.
|
||||
* The resulting iteration is in order of ascending field tag number. The object returned by {@link
|
||||
* #entrySet()} adheres to the same contract but is less efficient as it necessarily involves
|
||||
* creating an object for iteration.
|
||||
*
|
||||
* <p>The tradeoff for this memory efficiency is that the worst case running time of the {@code
|
||||
* put()} operation is {@code O(k + lg n)}, which happens when entries are added in descending
|
||||
* order. {@code k} should be chosen such that it covers enough common cases without adversely
|
||||
* affecting larger maps. In practice, the worst case scenario does not happen for extensions
|
||||
* because extension fields are serialized and deserialized in order of ascending tag number, but
|
||||
* the worst case scenario can happen for DynamicMessages.
|
||||
*
|
||||
* <p>The running time for all other operations is similar to that of {@code TreeMap}.
|
||||
*
|
||||
* <p>Instances are not thread-safe until {@link #makeImmutable()} is called, after which any
|
||||
* modifying operation will result in an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @author darick@google.com Darick Tong
|
||||
*/
|
||||
@ -87,15 +83,14 @@ import java.util.TreeMap;
|
||||
class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
|
||||
/**
|
||||
* Creates a new instance for mapping FieldDescriptors to their values.
|
||||
* The {@link #makeImmutable()} implementation will convert the List values
|
||||
* of any repeated fields to unmodifiable lists.
|
||||
* Creates a new instance for mapping FieldDescriptors to their values. The {@link
|
||||
* #makeImmutable()} implementation will convert the List values of any repeated fields to
|
||||
* unmodifiable lists.
|
||||
*
|
||||
* @param arraySize The size of the entry array containing the
|
||||
* lexicographically smallest mappings.
|
||||
* @param arraySize The size of the entry array containing the lexicographically smallest
|
||||
* mappings.
|
||||
*/
|
||||
static <FieldDescriptorType extends
|
||||
FieldSet.FieldDescriptorLite<FieldDescriptorType>>
|
||||
static <FieldDescriptorType extends FieldSet.FieldDescriptorLite<FieldDescriptorType>>
|
||||
SmallSortedMap<FieldDescriptorType, Object> newFieldMap(int arraySize) {
|
||||
return new SmallSortedMap<FieldDescriptorType, Object>(arraySize) {
|
||||
@Override
|
||||
@ -103,15 +98,13 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
public void makeImmutable() {
|
||||
if (!isImmutable()) {
|
||||
for (int i = 0; i < getNumArrayEntries(); i++) {
|
||||
final Map.Entry<FieldDescriptorType, Object> entry =
|
||||
getArrayEntryAt(i);
|
||||
final Map.Entry<FieldDescriptorType, Object> entry = getArrayEntryAt(i);
|
||||
if (entry.getKey().isRepeated()) {
|
||||
final List value = (List) entry.getValue();
|
||||
entry.setValue(Collections.unmodifiableList(value));
|
||||
}
|
||||
}
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry :
|
||||
getOverflowEntries()) {
|
||||
for (Map.Entry<FieldDescriptorType, Object> entry : getOverflowEntries()) {
|
||||
if (entry.getKey().isRepeated()) {
|
||||
final List value = (List) entry.getValue();
|
||||
entry.setValue(Collections.unmodifiableList(value));
|
||||
@ -126,11 +119,10 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
/**
|
||||
* Creates a new instance for testing.
|
||||
*
|
||||
* @param arraySize The size of the entry array containing the
|
||||
* lexicographically smallest mappings.
|
||||
* @param arraySize The size of the entry array containing the lexicographically smallest
|
||||
* mappings.
|
||||
*/
|
||||
static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest(
|
||||
int arraySize) {
|
||||
static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest(int arraySize) {
|
||||
return new SmallSortedMap<K, V>(arraySize);
|
||||
}
|
||||
|
||||
@ -146,9 +138,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
private volatile EntrySet lazyEntrySet;
|
||||
|
||||
/**
|
||||
* @code arraySize Size of the array in which the lexicographically smallest
|
||||
* mappings are stored. (i.e. the {@code k} referred to in the class
|
||||
* documentation).
|
||||
* @code arraySize Size of the array in which the lexicographically smallest mappings are stored.
|
||||
* (i.e. the {@code k} referred to in the class documentation).
|
||||
*/
|
||||
private SmallSortedMap(int arraySize) {
|
||||
this.maxArraySize = arraySize;
|
||||
@ -163,9 +154,10 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
// because none of the list's accessors are exposed. The iterator() of
|
||||
// overflowEntries, on the other hand, is exposed so it must be made
|
||||
// unmodifiable.
|
||||
overflowEntries = overflowEntries.isEmpty() ?
|
||||
Collections.<K, V>emptyMap() :
|
||||
Collections.unmodifiableMap(overflowEntries);
|
||||
overflowEntries =
|
||||
overflowEntries.isEmpty()
|
||||
? Collections.<K, V>emptyMap()
|
||||
: Collections.unmodifiableMap(overflowEntries);
|
||||
isImmutable = true;
|
||||
}
|
||||
}
|
||||
@ -192,9 +184,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
|
||||
/** @return An iterable over the overflow entries. */
|
||||
public Iterable<Map.Entry<K, V>> getOverflowEntries() {
|
||||
return overflowEntries.isEmpty() ?
|
||||
EmptySet.<Map.Entry<K, V>>iterable() :
|
||||
overflowEntries.entrySet();
|
||||
return overflowEntries.isEmpty()
|
||||
? EmptySet.<Map.Entry<K, V>>iterable()
|
||||
: overflowEntries.entrySet();
|
||||
}
|
||||
|
||||
|
||||
@ -204,10 +196,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The implementation throws a {@code ClassCastException} if o is not an
|
||||
* object of type {@code K}.
|
||||
* The implementation throws a {@code ClassCastException} if o is not an object of type {@code K}.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
@ -217,10 +208,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The implementation throws a {@code ClassCastException} if o is not an
|
||||
* object of type {@code K}.
|
||||
* The implementation throws a {@code ClassCastException} if o is not an object of type {@code K}.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public V get(Object o) {
|
||||
@ -251,8 +241,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
if (entryList.size() == maxArraySize) {
|
||||
// Shift the last array entry into overflow.
|
||||
final Entry lastEntryInArray = entryList.remove(maxArraySize - 1);
|
||||
getOverflowEntriesMutable().put(lastEntryInArray.getKey(),
|
||||
lastEntryInArray.getValue());
|
||||
getOverflowEntriesMutable().put(lastEntryInArray.getKey(), lastEntryInArray.getValue());
|
||||
}
|
||||
entryList.add(insertionPoint, new Entry(key, value));
|
||||
return null;
|
||||
@ -270,10 +259,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The implementation throws a {@code ClassCastException} if o is not an
|
||||
* object of type {@code K}.
|
||||
* The implementation throws a {@code ClassCastException} if o is not an object of type {@code K}.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public V remove(Object o) {
|
||||
@ -299,8 +287,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
if (!overflowEntries.isEmpty()) {
|
||||
// Shift the first entry in the overflow to be the last entry in the
|
||||
// array.
|
||||
final Iterator<Map.Entry<K, V>> iterator =
|
||||
getOverflowEntriesMutable().entrySet().iterator();
|
||||
final Iterator<Map.Entry<K, V>> iterator = getOverflowEntriesMutable().entrySet().iterator();
|
||||
entryList.add(new Entry(iterator.next()));
|
||||
iterator.remove();
|
||||
}
|
||||
@ -309,8 +296,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
|
||||
/**
|
||||
* @param key The key to find in the entry array.
|
||||
* @return The returned integer position follows the same semantics as the
|
||||
* value returned by {@link java.util.Arrays#binarySearch()}.
|
||||
* @return The returned integer position follows the same semantics as the value returned by
|
||||
* {@link java.util.Arrays#binarySearch()}.
|
||||
*/
|
||||
private int binarySearchInArray(K key) {
|
||||
int left = 0;
|
||||
@ -322,7 +309,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
if (right >= 0) {
|
||||
int cmp = key.compareTo(entryList.get(right).getKey());
|
||||
if (cmp > 0) {
|
||||
return -(right + 2); // Insert point is after "right".
|
||||
return -(right + 2); // Insert point is after "right".
|
||||
} else if (cmp == 0) {
|
||||
return right;
|
||||
}
|
||||
@ -343,11 +330,11 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to the AbstractMap implementation of {@code keySet()} and
|
||||
* {@code values()}, the entry set is created the first time this method is
|
||||
* called, and returned in response to all subsequent calls.
|
||||
* Similar to the AbstractMap implementation of {@code keySet()} and {@code values()}, the entry
|
||||
* set is created the first time this method is called, and returned in response to all subsequent
|
||||
* calls.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
@ -358,10 +345,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws UnsupportedOperationException if {@link #makeImmutable()} has
|
||||
* has been called.
|
||||
*/
|
||||
/** @throws UnsupportedOperationException if {@link #makeImmutable()} has has been called. */
|
||||
private void checkMutable() {
|
||||
if (isImmutable) {
|
||||
throw new UnsupportedOperationException();
|
||||
@ -369,10 +353,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@link SortedMap} to which overflow entries mappings can be
|
||||
* added or removed.
|
||||
* @throws UnsupportedOperationException if {@link #makeImmutable()} has been
|
||||
* called.
|
||||
* @return a {@link SortedMap} to which overflow entries mappings can be added or removed.
|
||||
* @throws UnsupportedOperationException if {@link #makeImmutable()} has been called.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private SortedMap<K, V> getOverflowEntriesMutable() {
|
||||
@ -383,10 +365,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
return (SortedMap<K, V>) overflowEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily creates the entry list. Any code that adds to the list must first
|
||||
* call this method.
|
||||
*/
|
||||
/** Lazily creates the entry list. Any code that adds to the list must first call this method. */
|
||||
private void ensureEntryArrayMutable() {
|
||||
checkMutable();
|
||||
if (entryList.isEmpty() && !(entryList instanceof ArrayList)) {
|
||||
@ -395,9 +374,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry implementation that implements Comparable in order to support
|
||||
* binary search within the entry array. Also checks mutability in
|
||||
* {@link #setValue()}.
|
||||
* Entry implementation that implements Comparable in order to support binary search within the
|
||||
* entry array. Also checks mutability in {@link #setValue()}.
|
||||
*/
|
||||
private class Entry implements Map.Entry<K, V>, Comparable<Entry> {
|
||||
|
||||
@ -451,8 +429,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (key == null ? 0 : key.hashCode()) ^
|
||||
(value == null ? 0 : value.hashCode());
|
||||
return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -466,9 +443,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stateless view of the entries in the field map.
|
||||
*/
|
||||
/** Stateless view of the entries in the field map. */
|
||||
private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
|
||||
|
||||
@Override
|
||||
@ -484,7 +459,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
/**
|
||||
* Throws a {@link ClassCastException} if o is not of the expected type.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
@ -492,8 +467,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
|
||||
final V existing = get(entry.getKey());
|
||||
final V value = entry.getValue();
|
||||
return existing == value ||
|
||||
(existing != null && existing.equals(value));
|
||||
return existing == value || (existing != null && existing.equals(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -508,7 +482,7 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
/**
|
||||
* Throws a {@link ClassCastException} if o is not of the expected type.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
* <p>{@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
@ -529,8 +503,8 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
|
||||
|
||||
/**
|
||||
* Iterator implementation that switches from the entry array to the overflow
|
||||
* entries appropriately.
|
||||
* Iterator implementation that switches from the entry array to the overflow entries
|
||||
* appropriately.
|
||||
*/
|
||||
private class EntryIterator implements Iterator<Map.Entry<K, V>> {
|
||||
|
||||
@ -571,10 +545,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* It is important to create the overflow iterator only after the array
|
||||
* entries have been iterated over because the overflow entry set changes
|
||||
* when the client calls remove() on the array entries, which invalidates
|
||||
* any existing iterators.
|
||||
* It is important to create the overflow iterator only after the array entries have been
|
||||
* iterated over because the overflow entry set changes when the client calls remove() on the
|
||||
* array entries, which invalidates any existing iterators.
|
||||
*/
|
||||
private Iterator<Map.Entry<K, V>> getOverflowIterator() {
|
||||
if (lazyOverflowIterator == null) {
|
||||
@ -585,9 +558,9 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class that holds immutable instances of an Iterable/Iterator that
|
||||
* we return when the overflow entries is empty. This eliminates the creation
|
||||
* of an Iterator object when there is nothing to iterate over.
|
||||
* Helper class that holds immutable instances of an Iterable/Iterator that we return when the
|
||||
* overflow entries is empty. This eliminates the creation of an Iterator object when there is
|
||||
* nothing to iterate over.
|
||||
*/
|
||||
private static class EmptySet {
|
||||
|
||||
@ -597,10 +570,12 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object next() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
@ -653,7 +628,6 @@ class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
|
||||
return overflowEntries.equals(other.overflowEntries);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,41 +30,58 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Provide text format escaping support for proto2 instances.
|
||||
*/
|
||||
/** Provide text format escaping support for proto2 instances. */
|
||||
final class TextFormatEscaper {
|
||||
private TextFormatEscaper() {}
|
||||
|
||||
private interface ByteSequence {
|
||||
int size();
|
||||
|
||||
byte byteAt(int offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes bytes in the format used in protocol buffer text format, which
|
||||
* is the same as the format used for C string literals. All bytes
|
||||
* that are not printable 7-bit ASCII characters are escaped, as well as
|
||||
* backslash, single-quote, and double-quote characters. Characters for
|
||||
* which no defined short-hand escape sequence is defined will be escaped
|
||||
* using 3-digit octal sequences.
|
||||
* Escapes bytes in the format used in protocol buffer text format, which is the same as the
|
||||
* format used for C string literals. All bytes that are not printable 7-bit ASCII characters are
|
||||
* escaped, as well as backslash, single-quote, and double-quote characters. Characters for which
|
||||
* no defined short-hand escape sequence is defined will be escaped using 3-digit octal sequences.
|
||||
*/
|
||||
static String escapeBytes(final ByteSequence input) {
|
||||
final StringBuilder builder = new StringBuilder(input.size());
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
final byte b = input.byteAt(i);
|
||||
switch (b) {
|
||||
// Java does not recognize \a or \v, apparently.
|
||||
case 0x07: builder.append("\\a"); break;
|
||||
case '\b': builder.append("\\b"); break;
|
||||
case '\f': builder.append("\\f"); break;
|
||||
case '\n': builder.append("\\n"); break;
|
||||
case '\r': builder.append("\\r"); break;
|
||||
case '\t': builder.append("\\t"); break;
|
||||
case 0x0b: builder.append("\\v"); break;
|
||||
case '\\': builder.append("\\\\"); break;
|
||||
case '\'': builder.append("\\\'"); break;
|
||||
case '"' : builder.append("\\\""); break;
|
||||
// Java does not recognize \a or \v, apparently.
|
||||
case 0x07:
|
||||
builder.append("\\a");
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
case 0x0b:
|
||||
builder.append("\\v");
|
||||
break;
|
||||
case '\\':
|
||||
builder.append("\\\\");
|
||||
break;
|
||||
case '\'':
|
||||
builder.append("\\\'");
|
||||
break;
|
||||
case '"':
|
||||
builder.append("\\\"");
|
||||
break;
|
||||
default:
|
||||
// Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
|
||||
// printable. Other byte values must be escaped.
|
||||
@ -83,54 +100,52 @@ final class TextFormatEscaper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes bytes in the format used in protocol buffer text format, which
|
||||
* is the same as the format used for C string literals. All bytes
|
||||
* that are not printable 7-bit ASCII characters are escaped, as well as
|
||||
* backslash, single-quote, and double-quote characters. Characters for
|
||||
* which no defined short-hand escape sequence is defined will be escaped
|
||||
* using 3-digit octal sequences.
|
||||
* Escapes bytes in the format used in protocol buffer text format, which is the same as the
|
||||
* format used for C string literals. All bytes that are not printable 7-bit ASCII characters are
|
||||
* escaped, as well as backslash, single-quote, and double-quote characters. Characters for which
|
||||
* no defined short-hand escape sequence is defined will be escaped using 3-digit octal sequences.
|
||||
*/
|
||||
static String escapeBytes(final ByteString input) {
|
||||
return escapeBytes(new ByteSequence() {
|
||||
@Override
|
||||
public int size() {
|
||||
return input.size();
|
||||
}
|
||||
@Override
|
||||
public byte byteAt(int offset) {
|
||||
return input.byteAt(offset);
|
||||
}
|
||||
});
|
||||
return escapeBytes(
|
||||
new ByteSequence() {
|
||||
@Override
|
||||
public int size() {
|
||||
return input.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte byteAt(int offset) {
|
||||
return input.byteAt(offset);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #escapeBytes(ByteString)}, but used for byte array.
|
||||
*/
|
||||
/** Like {@link #escapeBytes(ByteString)}, but used for byte array. */
|
||||
static String escapeBytes(final byte[] input) {
|
||||
return escapeBytes(new ByteSequence() {
|
||||
@Override
|
||||
public int size() {
|
||||
return input.length;
|
||||
}
|
||||
@Override
|
||||
public byte byteAt(int offset) {
|
||||
return input[offset];
|
||||
}
|
||||
});
|
||||
return escapeBytes(
|
||||
new ByteSequence() {
|
||||
@Override
|
||||
public int size() {
|
||||
return input.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte byteAt(int offset) {
|
||||
return input[offset];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #escapeBytes(ByteString)}, but escapes a text string.
|
||||
* Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
|
||||
* individually as a 3-digit octal escape. Yes, it's weird.
|
||||
* Like {@link #escapeBytes(ByteString)}, but escapes a text string. Non-ASCII characters are
|
||||
* first encoded as UTF-8, then each byte is escaped individually as a 3-digit octal escape. Yes,
|
||||
* it's weird.
|
||||
*/
|
||||
static String escapeText(final String input) {
|
||||
return escapeBytes(ByteString.copyFromUtf8(input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape double quotes and backslashes in a String for unicode output of a message.
|
||||
*/
|
||||
/** Escape double quotes and backslashes in a String for unicode output of a message. */
|
||||
static String escapeDoubleQuotesAndBackslashes(final String input) {
|
||||
return input.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -39,14 +38,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
/**
|
||||
* Data structure which is populated with the locations of each field value parsed from the text.
|
||||
*
|
||||
* <p>The locations of primary fields values are retrieved by {@code getLocation} or
|
||||
* {@code getLocations}. The locations of sub message values are within nested
|
||||
* {@code TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or
|
||||
* {@code getNestedTrees}.
|
||||
* <p>The locations of primary fields values are retrieved by {@code getLocation} or {@code
|
||||
* getLocations}. The locations of sub message values are within nested {@code
|
||||
* TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or {@code getNestedTrees}.
|
||||
*
|
||||
* <p>The {@code TextFormatParseInfoTree} is created by a Builder.
|
||||
*/
|
||||
@ -90,13 +87,13 @@ public class TextFormatParseInfoTree {
|
||||
this.subtreesFromField = Collections.unmodifiableMap(subs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the locations of a field.
|
||||
*
|
||||
* @param fieldDescriptor the the @{link FieldDescriptor} of the desired field
|
||||
* @return a list of the locations of values of the field. If there are not values
|
||||
* or the field doesn't exist, an empty list is returned.
|
||||
*/
|
||||
/**
|
||||
* Retrieve all the locations of a field.
|
||||
*
|
||||
* @param fieldDescriptor the @{link FieldDescriptor} of the desired field
|
||||
* @return a list of the locations of values of the field. If there are not values or the field
|
||||
* doesn't exist, an empty list is returned.
|
||||
*/
|
||||
public List<TextFormatParseLocation> getLocations(final FieldDescriptor fieldDescriptor) {
|
||||
List<TextFormatParseLocation> result = locationsFromField.get(fieldDescriptor);
|
||||
return (result == null) ? Collections.<TextFormatParseLocation>emptyList() : result;
|
||||
@ -134,7 +131,7 @@ public class TextFormatParseInfoTree {
|
||||
* @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message
|
||||
* @param index the index of message value.
|
||||
* @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field
|
||||
* doesn't exist or the index is out of range.
|
||||
* doesn't exist or the index is out of range.
|
||||
* @throws IllegalArgumentException if index is out of range
|
||||
*/
|
||||
public TextFormatParseInfoTree getNestedTree(final FieldDescriptor fieldDescriptor, int index) {
|
||||
@ -151,16 +148,16 @@ public class TextFormatParseInfoTree {
|
||||
}
|
||||
|
||||
private static <T> T getFromList(List<T> list, int index, FieldDescriptor fieldDescriptor) {
|
||||
if (index >= list.size() || index < 0) {
|
||||
throw new IllegalArgumentException(String.format("Illegal index field: %s, index %d",
|
||||
fieldDescriptor == null ? "<null>" : fieldDescriptor.getName(), index));
|
||||
if (index >= list.size() || index < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Illegal index field: %s, index %d",
|
||||
fieldDescriptor == null ? "<null>" : fieldDescriptor.getName(), index));
|
||||
}
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for a {@link TextFormatParseInfoTree}.
|
||||
*/
|
||||
/** Builder for a {@link TextFormatParseInfoTree}. */
|
||||
public static class Builder {
|
||||
|
||||
private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
|
||||
@ -169,9 +166,7 @@ public class TextFormatParseInfoTree {
|
||||
// sub message location information.
|
||||
private Map<FieldDescriptor, List<Builder>> subtreeBuildersFromField;
|
||||
|
||||
/**
|
||||
* Create a root level {@ParseInfoTree} builder.
|
||||
*/
|
||||
/** Create a root level {@ParseInfoTree} builder. */
|
||||
private Builder() {
|
||||
locationsFromField = new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
|
||||
subtreeBuildersFromField = new HashMap<FieldDescriptor, List<Builder>>();
|
||||
|
@ -39,9 +39,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
public final class TextFormatParseLocation {
|
||||
|
||||
/**
|
||||
* The empty location.
|
||||
*/
|
||||
/** The empty location. */
|
||||
public static final TextFormatParseLocation EMPTY = new TextFormatParseLocation(-1, -1);
|
||||
|
||||
/**
|
||||
@ -92,8 +90,7 @@ public final class TextFormatParseLocation {
|
||||
return false;
|
||||
}
|
||||
TextFormatParseLocation that = (TextFormatParseLocation) o;
|
||||
return (this.line == that.getLine())
|
||||
&& (this.column == that.getColumn());
|
||||
return (this.line == that.getLine()) && (this.column == that.getColumn());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,15 +34,13 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Thrown when attempting to build a protocol message that is missing required
|
||||
* fields. This is a {@code RuntimeException} because it normally represents
|
||||
* a programming error: it happens when some code which constructs a message
|
||||
* fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
|
||||
* throw this; they throw an {@link InvalidProtocolBufferException} if
|
||||
* required fields are missing, because it is not a programming error to
|
||||
* receive an incomplete message. In other words,
|
||||
* {@code UninitializedMessageException} should never be thrown by correct
|
||||
* code, but {@code InvalidProtocolBufferException} might be.
|
||||
* Thrown when attempting to build a protocol message that is missing required fields. This is a
|
||||
* {@code RuntimeException} because it normally represents a programming error: it happens when some
|
||||
* code which constructs a message fails to set all the fields. {@code parseFrom()} methods <b>do
|
||||
* not</b> throw this; they throw an {@link InvalidProtocolBufferException} if required fields are
|
||||
* missing, because it is not a programming error to receive an incomplete message. In other words,
|
||||
* {@code UninitializedMessageException} should never be thrown by correct code, but {@code
|
||||
* InvalidProtocolBufferException} might be.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -50,8 +48,9 @@ public class UninitializedMessageException extends RuntimeException {
|
||||
private static final long serialVersionUID = -7466929953374883507L;
|
||||
|
||||
public UninitializedMessageException(final MessageLite message) {
|
||||
super("Message was missing required fields. (Lite runtime could not " +
|
||||
"determine which fields were missing).");
|
||||
super(
|
||||
"Message was missing required fields. (Lite runtime could not "
|
||||
+ "determine which fields were missing).");
|
||||
missingFields = null;
|
||||
}
|
||||
|
||||
@ -63,19 +62,18 @@ public class UninitializedMessageException extends RuntimeException {
|
||||
private final List<String> missingFields;
|
||||
|
||||
/**
|
||||
* Get a list of human-readable names of required fields missing from this
|
||||
* message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
|
||||
* Returns null if the lite runtime was used, since it lacks the ability to
|
||||
* find missing fields.
|
||||
* Get a list of human-readable names of required fields missing from this message. Each name is a
|
||||
* full path to a field, e.g. "foo.bar[5].baz". Returns null if the lite runtime was used, since
|
||||
* it lacks the ability to find missing fields.
|
||||
*/
|
||||
public List<String> getMissingFields() {
|
||||
return Collections.unmodifiableList(missingFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this exception to an {@link InvalidProtocolBufferException}.
|
||||
* When a parsed message is missing required fields, this should be thrown
|
||||
* instead of {@code UninitializedMessageException}.
|
||||
* Converts this exception to an {@link InvalidProtocolBufferException}. When a parsed message is
|
||||
* missing required fields, this should be thrown instead of {@code
|
||||
* UninitializedMessageException}.
|
||||
*/
|
||||
public InvalidProtocolBufferException asInvalidProtocolBufferException() {
|
||||
return new InvalidProtocolBufferException(getMessage());
|
||||
@ -83,8 +81,7 @@ public class UninitializedMessageException extends RuntimeException {
|
||||
|
||||
/** Construct the description string for this exception. */
|
||||
private static String buildDescription(final List<String> missingFields) {
|
||||
final StringBuilder description =
|
||||
new StringBuilder("Message missing required fields: ");
|
||||
final StringBuilder description = new StringBuilder("Message missing required fields: ");
|
||||
boolean first = true;
|
||||
for (final String field : missingFields) {
|
||||
if (first) {
|
||||
|
@ -43,14 +43,13 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* {@code UnknownFieldSet} 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.
|
||||
* {@code UnknownFieldSet} 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>Every {@link Message} contains an {@code UnknownFieldSet} (and every
|
||||
* {@link Message.Builder} contains an {@link Builder}).
|
||||
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every {@link Message.Builder}
|
||||
* contains an {@link Builder}).
|
||||
*
|
||||
* <p>Most users will never need to use this class.
|
||||
*
|
||||
@ -67,10 +66,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return Builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Builder} and initialize it to be a copy
|
||||
* of {@code copyFrom}.
|
||||
*/
|
||||
/** Create a new {@link Builder} and initialize it to be a copy of {@code copyFrom}. */
|
||||
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
|
||||
return newBuilder().mergeFrom(copyFrom);
|
||||
}
|
||||
@ -79,22 +75,23 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
public static UnknownFieldSet getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
private static final UnknownFieldSet defaultInstance =
|
||||
new UnknownFieldSet(Collections.<Integer, Field>emptyMap(),
|
||||
Collections.<Integer, Field>emptyMap());
|
||||
new UnknownFieldSet(
|
||||
Collections.<Integer, Field>emptyMap(), Collections.<Integer, Field>emptyMap());
|
||||
|
||||
/**
|
||||
* Construct an {@code UnknownFieldSet} around the given map. The map is
|
||||
* expected to be immutable.
|
||||
* Construct an {@code UnknownFieldSet} around the given map. The map is expected to be immutable.
|
||||
*/
|
||||
UnknownFieldSet(final Map<Integer, Field> fields,
|
||||
final Map<Integer, Field> fieldsDescending) {
|
||||
UnknownFieldSet(final Map<Integer, Field> fields, final Map<Integer, Field> fieldsDescending) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
private final Map<Integer, Field> fields;
|
||||
|
||||
|
||||
@ -103,8 +100,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
return (other instanceof UnknownFieldSet) &&
|
||||
fields.equals(((UnknownFieldSet) other).fields);
|
||||
return (other instanceof UnknownFieldSet) && fields.equals(((UnknownFieldSet) other).fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -122,10 +118,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return fields.containsKey(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field by number. Returns an empty field if not present. Never
|
||||
* returns {@code null}.
|
||||
*/
|
||||
/** Get a field by number. Returns an empty field if not present. Never returns {@code null}. */
|
||||
public Field getField(final int number) {
|
||||
final Field result = fields.get(number);
|
||||
return (result == null) ? Field.getDefaultInstance() : result;
|
||||
@ -141,9 +134,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the set to a string in protocol buffer text format. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link TextFormat#printToString(UnknownFieldSet)}.
|
||||
* Converts the set to a string in protocol buffer text format. This is just a trivial wrapper
|
||||
* around {@link TextFormat#printToString(UnknownFieldSet)}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -151,26 +143,24 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is
|
||||
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is just a trivial wrapper
|
||||
* around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public ByteString toByteString() {
|
||||
try {
|
||||
final ByteString.CodedBuilder out =
|
||||
ByteString.newCodedBuilder(getSerializedSize());
|
||||
final ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize());
|
||||
writeTo(out.getCodedOutput());
|
||||
return out.build();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
"Serializing to a ByteString threw an IOException (should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code byte} array and returns it. This is
|
||||
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
* Serializes the message to a {@code byte} array and returns it. This is just a trivial wrapper
|
||||
* around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
@ -182,14 +172,13 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return result;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a byte array threw an IOException " +
|
||||
"(should never happen).", e);
|
||||
"Serializing to a byte array threw an IOException (should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This is just a
|
||||
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
* Serializes the message and writes it to {@code output}. This is just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(final OutputStream output) throws IOException {
|
||||
@ -216,15 +205,10 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the set and writes it to {@code output} using
|
||||
* {@code MessageSet} wire format.
|
||||
*/
|
||||
public void writeAsMessageSetTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
/** Serializes the set and writes it to {@code output} using {@code MessageSet} wire format. */
|
||||
public void writeAsMessageSetTo(final CodedOutputStream output) throws IOException {
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
entry.getValue().writeAsMessageSetExtensionTo(
|
||||
entry.getKey(), output);
|
||||
entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,8 +217,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
public int getSerializedSizeAsMessageSet() {
|
||||
int result = 0;
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
|
||||
entry.getKey());
|
||||
result += entry.getValue().getSerializedSizeAsMessageSetExtension(entry.getKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -247,8 +230,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/** Parse an {@code UnknownFieldSet} from the given input stream. */
|
||||
public static UnknownFieldSet parseFrom(final CodedInputStream input)
|
||||
throws IOException {
|
||||
public static UnknownFieldSet parseFrom(final CodedInputStream input) throws IOException {
|
||||
return newBuilder().mergeFrom(input).build();
|
||||
}
|
||||
|
||||
@ -259,14 +241,12 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
|
||||
public static UnknownFieldSet parseFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
public static UnknownFieldSet parseFrom(final byte[] data) throws InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).build();
|
||||
}
|
||||
|
||||
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
|
||||
public static UnknownFieldSet parseFrom(final InputStream input)
|
||||
throws IOException {
|
||||
public static UnknownFieldSet parseFrom(final InputStream input) throws IOException {
|
||||
return newBuilder().mergeFrom(input).build();
|
||||
}
|
||||
|
||||
@ -283,12 +263,11 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
/**
|
||||
* Builder for {@link UnknownFieldSet}s.
|
||||
*
|
||||
* <p>Note that this class maintains {@link Field.Builder}s for all fields
|
||||
* in the set. Thus, adding one element to an existing {@link Field} does not
|
||||
* require making a copy. This is important for efficient parsing of
|
||||
* unknown repeated fields. However, it implies that {@link Field}s cannot
|
||||
* be constructed independently, nor can two {@link UnknownFieldSet}s share
|
||||
* the same {@code Field} object.
|
||||
* <p>Note that this class maintains {@link Field.Builder}s for all fields in the set. Thus,
|
||||
* adding one element to an existing {@link Field} does not require making a copy. This is
|
||||
* important for efficient parsing of unknown repeated fields. However, it implies that {@link
|
||||
* Field}s cannot be constructed independently, nor can two {@link UnknownFieldSet}s share the
|
||||
* same {@code Field} object.
|
||||
*
|
||||
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
|
||||
*/
|
||||
@ -311,8 +290,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field builder for the given field number which includes any
|
||||
* values that already exist.
|
||||
* Get a field builder for the given field number which includes any values that already exist.
|
||||
*/
|
||||
private Field.Builder getFieldBuilder(final int number) {
|
||||
if (lastField != null) {
|
||||
@ -338,10 +316,9 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
/**
|
||||
* Build the {@link UnknownFieldSet} 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 NullPointerException} to be
|
||||
* thrown.
|
||||
* <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 NullPointerException} to be thrown.
|
||||
*/
|
||||
@Override
|
||||
public UnknownFieldSet build() {
|
||||
@ -365,10 +342,9 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
|
||||
@Override
|
||||
public Builder clone() {
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
Map<Integer, Field> descendingFields = null;
|
||||
return UnknownFieldSet.newBuilder().mergeFrom(
|
||||
new UnknownFieldSet(fields, descendingFields));
|
||||
return UnknownFieldSet.newBuilder().mergeFrom(new UnknownFieldSet(fields, descendingFields));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -388,7 +364,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
reinitialize();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** Clear fields from the set with a given field number. */
|
||||
public Builder clearField(final int number) {
|
||||
if (number == 0) {
|
||||
@ -406,9 +382,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the fields from {@code other} into this set. If a field number
|
||||
* exists in both sets, {@code other}'s values for that field will be
|
||||
* appended to the values in this set.
|
||||
* Merge the fields from {@code other} into this set. If a field number exists in both sets,
|
||||
* {@code other}'s values for that field will be appended to the values in this set.
|
||||
*/
|
||||
public Builder mergeFrom(final UnknownFieldSet other) {
|
||||
if (other != getDefaultInstance()) {
|
||||
@ -420,8 +395,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
||||
* number already exists, the two are merged.
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists,
|
||||
* the two are merged.
|
||||
*/
|
||||
public Builder mergeField(final int number, final Field field) {
|
||||
if (number == 0) {
|
||||
@ -439,9 +414,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for merging a new field containing a single varint
|
||||
* value. This is used in particular when an unknown enum value is
|
||||
* encountered.
|
||||
* Convenience method for merging a new field containing a single varint value. This is used in
|
||||
* particular when an unknown enum value is encountered.
|
||||
*/
|
||||
public Builder mergeVarintField(final int number, final int value) {
|
||||
if (number == 0) {
|
||||
@ -451,14 +425,12 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method for merging a length-delimited field.
|
||||
*
|
||||
* <p>For use by generated code only.
|
||||
*/
|
||||
public Builder mergeLengthDelimitedField(
|
||||
final int number, final ByteString value) {
|
||||
public Builder mergeLengthDelimitedField(final int number, final ByteString value) {
|
||||
if (number == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
@ -475,8 +447,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
||||
* number already exists, it is removed.
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists,
|
||||
* it is removed.
|
||||
*/
|
||||
public Builder addField(final int number, final Field field) {
|
||||
if (number == 0) {
|
||||
@ -488,25 +460,22 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
lastFieldNumber = 0;
|
||||
}
|
||||
if (fields.isEmpty()) {
|
||||
fields = new TreeMap<Integer,Field>();
|
||||
fields = new TreeMap<Integer, Field>();
|
||||
}
|
||||
fields.put(number, field);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all present {@code Field}s as an immutable {@code Map}. If more
|
||||
* fields are added, the changes may or may not be reflected in this map.
|
||||
* Get all present {@code Field}s as an immutable {@code Map}. If more fields are added, the
|
||||
* changes may or may not be reflected in this map.
|
||||
*/
|
||||
public Map<Integer, Field> asMap() {
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
return Collections.unmodifiableMap(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an entire message from {@code input} and merge its fields into
|
||||
* this set.
|
||||
*/
|
||||
/** Parse an entire message from {@code input} and merge its fields into this set. */
|
||||
@Override
|
||||
public Builder mergeFrom(final CodedInputStream input) throws IOException {
|
||||
while (true) {
|
||||
@ -520,11 +489,11 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
|
||||
/**
|
||||
* Parse a single field from {@code input} and merge it into this set.
|
||||
*
|
||||
* @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 {
|
||||
public boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
|
||||
final int number = WireFormat.getTagFieldNumber(tag);
|
||||
switch (WireFormat.getTagWireType(tag)) {
|
||||
case WireFormat.WIRETYPE_VARINT:
|
||||
@ -538,8 +507,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
final Builder subBuilder = newBuilder();
|
||||
input.readGroup(number, subBuilder,
|
||||
ExtensionRegistry.getEmptyRegistry());
|
||||
input.readGroup(number, subBuilder, ExtensionRegistry.getEmptyRegistry());
|
||||
getFieldBuilder(number).addGroup(subBuilder.build());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_END_GROUP:
|
||||
@ -553,9 +521,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the set being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
|
||||
@ -568,15 +535,13 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
throw e;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
"Reading from a ByteString threw an IOException (should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the set being built. This
|
||||
* is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
|
||||
@ -589,15 +554,13 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
throw e;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
"Reading from a byte array threw an IOException (should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the set being built.
|
||||
* This is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final InputStream input) throws IOException {
|
||||
@ -643,8 +606,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
@Override
|
||||
public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return this;
|
||||
@ -652,8 +614,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
"Reading from a byte array threw an IOException (should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -698,19 +659,15 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
/**
|
||||
* Represents a single field in an {@code UnknownFieldSet}.
|
||||
*
|
||||
* <p>A {@code Field} consists of five lists of values. The lists correspond
|
||||
* to the five "wire types" used in the protocol buffer binary format.
|
||||
* The wire type of each field can be determined from the encoded form alone,
|
||||
* without knowing the field's declared type. So, we are able to parse
|
||||
* unknown values at least this far and separate them. Normally, only one
|
||||
* of the five lists will contain any values, since it is impossible to
|
||||
* define a valid message type that declares two different types for the
|
||||
* same field number. However, the code is designed to allow for the case
|
||||
* where the same unknown field number is encountered using multiple different
|
||||
* wire types.
|
||||
* <p>A {@code Field} consists of five lists of values. The lists correspond to the five "wire
|
||||
* types" used in the protocol buffer binary format. The wire type of each field can be determined
|
||||
* from the encoded form alone, without knowing the field's declared type. So, we are able to
|
||||
* parse unknown values at least this far and separate them. Normally, only one of the five lists
|
||||
* will contain any values, since it is impossible to define a valid message type that declares
|
||||
* two different types for the same field number. However, the code is designed to allow for the
|
||||
* case where the same unknown field number is encountered using multiple different wire types.
|
||||
*
|
||||
* <p>{@code Field} is an immutable class. To construct one, you must use a
|
||||
* {@link Builder}.
|
||||
* <p>{@code Field} is an immutable class. To construct one, you must use a {@link Builder}.
|
||||
*
|
||||
* @see UnknownFieldSet
|
||||
*/
|
||||
@ -722,10 +679,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return Builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link Builder} and initialize it to a copy of
|
||||
* {@code copyFrom}.
|
||||
*/
|
||||
/** Construct a new {@link Builder} and initialize it to a copy of {@code copyFrom}. */
|
||||
public static Builder newBuilder(final Field copyFrom) {
|
||||
return newBuilder().mergeFrom(copyFrom);
|
||||
}
|
||||
@ -734,26 +688,36 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
public static Field getDefaultInstance() {
|
||||
return fieldDefaultInstance;
|
||||
}
|
||||
|
||||
private static final Field fieldDefaultInstance = newBuilder().build();
|
||||
|
||||
/** Get the list of varint values for this field. */
|
||||
public List<Long> getVarintList() { return varint; }
|
||||
public List<Long> getVarintList() {
|
||||
return varint;
|
||||
}
|
||||
|
||||
/** Get the list of fixed32 values for this field. */
|
||||
public List<Integer> getFixed32List() { return fixed32; }
|
||||
public List<Integer> getFixed32List() {
|
||||
return fixed32;
|
||||
}
|
||||
|
||||
/** Get the list of fixed64 values for this field. */
|
||||
public List<Long> getFixed64List() { return fixed64; }
|
||||
public List<Long> getFixed64List() {
|
||||
return fixed64;
|
||||
}
|
||||
|
||||
/** Get the list of length-delimited values for this field. */
|
||||
public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
|
||||
public List<ByteString> getLengthDelimitedList() {
|
||||
return lengthDelimited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of embedded group values for this field. These are
|
||||
* represented using {@link UnknownFieldSet}s rather than {@link Message}s
|
||||
* since the group's type is presumably unknown.
|
||||
* Get the list of embedded group values for this field. These are represented using {@link
|
||||
* UnknownFieldSet}s rather than {@link Message}s since the group's type is presumably unknown.
|
||||
*/
|
||||
public List<UnknownFieldSet> getGroupList() { return group; }
|
||||
public List<UnknownFieldSet> getGroupList() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
@ -763,8 +727,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
if (!(other instanceof Field)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(getIdentityArray(),
|
||||
((Field) other).getIdentityArray());
|
||||
return Arrays.equals(getIdentityArray(), ((Field) other).getIdentityArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -772,17 +735,9 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
return Arrays.hashCode(getIdentityArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of objects to be used to uniquely identify this
|
||||
* {@link Field} instance.
|
||||
*/
|
||||
/** Returns the array of objects to be used to uniquely identify this {@link Field} instance. */
|
||||
private Object[] getIdentityArray() {
|
||||
return new Object[] {
|
||||
varint,
|
||||
fixed32,
|
||||
fixed64,
|
||||
lengthDelimited,
|
||||
group};
|
||||
return new Object[] {varint, fixed32, fixed64, lengthDelimited, group};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -802,12 +757,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the field, including field number, and writes it to
|
||||
* {@code output}.
|
||||
*/
|
||||
public void writeTo(final int fieldNumber, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
/** Serializes the field, including field number, and writes it to {@code output}. */
|
||||
public void writeTo(final int fieldNumber, final CodedOutputStream output) throws IOException {
|
||||
for (final long value : varint) {
|
||||
output.writeUInt64(fieldNumber, value);
|
||||
}
|
||||
@ -825,10 +776,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this field, including field
|
||||
* number.
|
||||
*/
|
||||
/** Get the number of bytes required to encode this field, including field number. */
|
||||
public int getSerializedSize(final int fieldNumber) {
|
||||
int result = 0;
|
||||
for (final long value : varint) {
|
||||
@ -850,12 +798,10 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the field, including field number, and writes it to
|
||||
* {@code output}, using {@code MessageSet} wire format.
|
||||
* Serializes the field, including field number, and writes it to {@code output}, using {@code
|
||||
* MessageSet} wire format.
|
||||
*/
|
||||
public void writeAsMessageSetExtensionTo(
|
||||
final int fieldNumber,
|
||||
final CodedOutputStream output)
|
||||
public void writeAsMessageSetExtensionTo(final int fieldNumber, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
output.writeRawMessageSetExtension(fieldNumber, value);
|
||||
@ -870,8 +816,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
|
||||
int result = 0;
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
result += CodedOutputStream.computeRawMessageSetExtensionSize(
|
||||
fieldNumber, value);
|
||||
result += CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -900,10 +845,9 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
private Field result;
|
||||
|
||||
/**
|
||||
* Build the field. After {@code build()} has been called, the
|
||||
* {@code Builder} is no longer usable. Calling any other method will
|
||||
* result in undefined behavior and can cause a
|
||||
* {@code NullPointerException} to be thrown.
|
||||
* Build the field. After {@code build()} has been called, the {@code Builder} is no longer
|
||||
* usable. Calling any other method will result in undefined behavior and can cause a {@code
|
||||
* NullPointerException} to be thrown.
|
||||
*/
|
||||
public Field build() {
|
||||
if (result.varint == null) {
|
||||
@ -924,8 +868,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
if (result.lengthDelimited == null) {
|
||||
result.lengthDelimited = Collections.emptyList();
|
||||
} else {
|
||||
result.lengthDelimited =
|
||||
Collections.unmodifiableList(result.lengthDelimited);
|
||||
result.lengthDelimited = Collections.unmodifiableList(result.lengthDelimited);
|
||||
}
|
||||
if (result.group == null) {
|
||||
result.group = Collections.emptyList();
|
||||
@ -945,9 +888,8 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the values in {@code other} into this field. For each list
|
||||
* of values, {@code other}'s values are append to the ones in this
|
||||
* field.
|
||||
* Merge the values in {@code other} into this field. For each list of values, {@code other}'s
|
||||
* values are append to the ones in this field.
|
||||
*/
|
||||
public Builder mergeFrom(final Field other) {
|
||||
if (!other.varint.isEmpty()) {
|
||||
@ -1030,9 +972,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser to implement MessageLite interface.
|
||||
*/
|
||||
/** Parser to implement MessageLite interface. */
|
||||
public static final class Parser extends AbstractParser<UnknownFieldSet> {
|
||||
@Override
|
||||
public UnknownFieldSet parsePartialFrom(
|
||||
@ -1044,14 +984,14 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (IOException e) {
|
||||
throw new InvalidProtocolBufferException(e)
|
||||
.setUnfinishedMessage(builder.buildPartial());
|
||||
throw new InvalidProtocolBufferException(e).setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Parser PARSER = new Parser();
|
||||
|
||||
@Override
|
||||
public final Parser getParserForType() {
|
||||
return PARSER;
|
||||
|
@ -34,24 +34,23 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
* {@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 {
|
||||
|
||||
|
||||
// Arbitrarily chosen.
|
||||
// TODO(dweis): Tune this number?
|
||||
private static final int MIN_CAPACITY = 8;
|
||||
|
||||
private static final UnknownFieldSetLite DEFAULT_INSTANCE =
|
||||
new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */);
|
||||
new UnknownFieldSetLite(0, new int[0], new Object[0], /* isMutable= */ false);
|
||||
|
||||
/**
|
||||
* Get an empty {@code UnknownFieldSetLite}.
|
||||
@ -61,17 +60,15 @@ public final class UnknownFieldSetLite {
|
||||
public static UnknownFieldSetLite getDefaultInstance() {
|
||||
return DEFAULT_INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mutable instance.
|
||||
*/
|
||||
|
||||
/** Returns a new mutable instance. */
|
||||
static UnknownFieldSetLite newInstance() {
|
||||
return new UnknownFieldSetLite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and
|
||||
* {@code second}.
|
||||
* Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and {@code
|
||||
* second}.
|
||||
*/
|
||||
static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) {
|
||||
int count = first.count + second.count;
|
||||
@ -79,66 +76,50 @@ public final class UnknownFieldSetLite {
|
||||
System.arraycopy(second.tags, 0, tags, first.count, second.count);
|
||||
Object[] objects = Arrays.copyOf(first.objects, count);
|
||||
System.arraycopy(second.objects, 0, objects, first.count, second.count);
|
||||
return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
|
||||
return new UnknownFieldSetLite(count, tags, objects, /* isMutable= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of elements in the set.
|
||||
*/
|
||||
/** The number of elements in the set. */
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* The tag numbers for the elements in the set.
|
||||
*/
|
||||
|
||||
/** The tag numbers for the elements in the set. */
|
||||
private int[] tags;
|
||||
|
||||
/**
|
||||
* The boxed values of the elements in the set.
|
||||
*/
|
||||
|
||||
/** The boxed values of the elements in the set. */
|
||||
private Object[] objects;
|
||||
|
||||
/**
|
||||
* The lazily computed serialized size of the set.
|
||||
*/
|
||||
|
||||
/** The lazily computed serialized size of the set. */
|
||||
private int memoizedSerializedSize = -1;
|
||||
|
||||
/**
|
||||
* Indicates that this object is mutable.
|
||||
*/
|
||||
|
||||
/** Indicates that this object is mutable. */
|
||||
private boolean isMutable;
|
||||
|
||||
/**
|
||||
* Constructs a mutable {@code UnknownFieldSetLite}.
|
||||
*/
|
||||
/** Constructs a mutable {@code UnknownFieldSetLite}. */
|
||||
private UnknownFieldSetLite() {
|
||||
this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */);
|
||||
this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], /* isMutable= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the {@code UnknownFieldSetLite}.
|
||||
*/
|
||||
|
||||
/** Constructs the {@code UnknownFieldSetLite}. */
|
||||
private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) {
|
||||
this.count = count;
|
||||
this.tags = tags;
|
||||
this.objects = objects;
|
||||
this.isMutable = isMutable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks this object as immutable.
|
||||
*
|
||||
*
|
||||
* <p>Future calls to methods that attempt to modify this object will throw.
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
this.isMutable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an {@link UnsupportedOperationException} if immutable.
|
||||
*/
|
||||
|
||||
/** Throws an {@link UnsupportedOperationException} if immutable. */
|
||||
void checkMutable() {
|
||||
if (!isMutable) {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,17 +178,17 @@ public final class UnknownFieldSetLite {
|
||||
if (size != -1) {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
size = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int tag = tags[i];
|
||||
int fieldNumber = WireFormat.getTagFieldNumber(tag);
|
||||
size += CodedOutputStream.computeRawMessageSetExtensionSize(
|
||||
fieldNumber, (ByteString) objects[i]);
|
||||
size +=
|
||||
CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, (ByteString) objects[i]);
|
||||
}
|
||||
|
||||
|
||||
memoizedSerializedSize = size;
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -221,7 +202,7 @@ public final class UnknownFieldSetLite {
|
||||
if (size != -1) {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
size = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
int tag = tags[i];
|
||||
@ -240,19 +221,20 @@ public final class UnknownFieldSetLite {
|
||||
size += CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) objects[i]);
|
||||
break;
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
size += CodedOutputStream.computeTagSize(fieldNumber) * 2
|
||||
+ ((UnknownFieldSetLite) objects[i]).getSerializedSize();
|
||||
size +=
|
||||
CodedOutputStream.computeTagSize(fieldNumber) * 2
|
||||
+ ((UnknownFieldSetLite) objects[i]).getSerializedSize();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(InvalidProtocolBufferException.invalidWireType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memoizedSerializedSize = size;
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
private static boolean equals(int[] tags1, int[] tags2, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (tags1[i] != tags2[i]) {
|
||||
@ -284,8 +266,8 @@ public final class UnknownFieldSetLite {
|
||||
if (!(obj instanceof UnknownFieldSetLite)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UnknownFieldSetLite other = (UnknownFieldSetLite) obj;
|
||||
|
||||
UnknownFieldSetLite other = (UnknownFieldSetLite) obj;
|
||||
if (count != other.count
|
||||
|| !equals(tags, other.tags, count)
|
||||
|| !equals(objects, other.objects, count)) {
|
||||
@ -341,25 +323,23 @@ public final class UnknownFieldSetLite {
|
||||
void storeField(int tag, Object value) {
|
||||
checkMutable();
|
||||
ensureCapacity();
|
||||
|
||||
|
||||
tags[count] = tag;
|
||||
objects[count] = value;
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that our arrays are long enough to store more metadata.
|
||||
*/
|
||||
|
||||
/** Ensures that our arrays are long enough to store more metadata. */
|
||||
private void ensureCapacity() {
|
||||
if (count == tags.length) {
|
||||
if (count == tags.length) {
|
||||
int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
|
||||
int newLength = count + increment;
|
||||
|
||||
|
||||
tags = Arrays.copyOf(tags, newLength);
|
||||
objects = Arrays.copyOf(objects, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a single field from {@code input} and merge it into this set.
|
||||
*
|
||||
@ -387,8 +367,7 @@ public final class UnknownFieldSetLite {
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite();
|
||||
subFieldSet.mergeFrom(input);
|
||||
input.checkLastTagWas(
|
||||
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
|
||||
input.checkLastTagWas(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
|
||||
storeField(tag, subFieldSet);
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_END_GROUP:
|
||||
@ -399,9 +378,8 @@ public final class UnknownFieldSetLite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for merging a new field containing a single varint
|
||||
* value. This is used in particular when an unknown enum value is
|
||||
* encountered.
|
||||
* 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.
|
||||
*/
|
||||
@ -412,7 +390,7 @@ public final class UnknownFieldSetLite {
|
||||
}
|
||||
|
||||
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -421,21 +399,18 @@ public final class UnknownFieldSetLite {
|
||||
*
|
||||
* <p>For use by generated code only.
|
||||
*/
|
||||
UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
|
||||
UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
|
||||
checkMutable();
|
||||
if (fieldNumber == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
|
||||
storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an entire message from {@code input} and merge its fields into
|
||||
* this set.
|
||||
*/
|
||||
|
||||
/** Parse an entire message from {@code input} and merge its fields into this set. */
|
||||
private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException {
|
||||
// Ensures initialization in mergeFieldFrom.
|
||||
while (true) {
|
||||
|
@ -39,8 +39,8 @@ import java.util.ListIterator;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link LazyStringList} that wraps another
|
||||
* {@link LazyStringList} such that it cannot be modified via the wrapper.
|
||||
* An implementation of {@link LazyStringList} that wraps another {@link LazyStringList} such that
|
||||
* it cannot be modified via the wrapper.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@ -57,7 +57,7 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
|
||||
public String get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getRaw(int index) {
|
||||
return list.getRaw(index);
|
||||
@ -97,7 +97,7 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
|
||||
public void add(byte[] element) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(int index, byte[] element) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -39,23 +39,24 @@ import java.nio.ByteBuffer;
|
||||
* potentially expose the backing buffer of a {@link ByteString} to the application.
|
||||
*
|
||||
* <p><strong>DISCLAIMER:</strong> The methods in this class should only be called if it is
|
||||
* guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a
|
||||
* {@link ByteString} can lead to unexpected and undesirable consequences in your application,
|
||||
* and will likely be difficult to debug. Proceed with caution!
|
||||
* guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a {@link
|
||||
* ByteString} can lead to unexpected and undesirable consequences in your application, and will
|
||||
* likely be difficult to debug. Proceed with caution!
|
||||
*
|
||||
* <p>This can have a number of significant side affects that have spooky-action-at-a-distance-like
|
||||
* behavior. In particular, if the bytes value changes out from under a Protocol Buffer:
|
||||
*
|
||||
* <p>This can have a number of significant side affects that have
|
||||
* spooky-action-at-a-distance-like behavior. In particular, if the bytes value changes out from
|
||||
* under a Protocol Buffer:
|
||||
* <ul>
|
||||
* <li>serialization may throw
|
||||
* <li>serialization may succeed but the wrong bytes may be written out
|
||||
* <li>messages are no longer threadsafe
|
||||
* <li>hashCode may be incorrect
|
||||
* <ul>
|
||||
* <li>can result in a permanent memory leak when used as a key in a long-lived HashMap
|
||||
* <li> the semantics of many programs may be violated if this is the case
|
||||
* </ul>
|
||||
* <li>serialization may throw
|
||||
* <li>serialization may succeed but the wrong bytes may be written out
|
||||
* <li>messages are no longer threadsafe
|
||||
* <li>hashCode may be incorrect
|
||||
* <ul>
|
||||
* <li>can result in a permanent memory leak when used as a key in a long-lived HashMap
|
||||
* <li>the semantics of many programs may be violated if this is the case
|
||||
* </ul>
|
||||
* </ul>
|
||||
*
|
||||
* Each of these issues will occur in parts of the code base that are entirely distinct from the
|
||||
* parts of the code base modifying the buffer. In fact, both parts of the code base may be correct
|
||||
* - it is the bridging with the unsafe operations that was in error!
|
||||
@ -99,19 +100,19 @@ public final class UnsafeByteOperations {
|
||||
|
||||
/**
|
||||
* Writes the given {@link ByteString} to the provided {@link ByteOutput}. Calling this method may
|
||||
* result in multiple operations on the target {@link ByteOutput}
|
||||
* (i.e. for roped {@link ByteString}s).
|
||||
* result in multiple operations on the target {@link ByteOutput} (i.e. for roped {@link
|
||||
* ByteString}s).
|
||||
*
|
||||
* <p>This method exposes the internal backing buffer(s) of the {@link ByteString} to the {@link
|
||||
* ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
|
||||
* {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
|
||||
*
|
||||
* <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
|
||||
* so may result in corrupted data, which would be difficult to debug.
|
||||
* <p>NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing so
|
||||
* may result in corrupted data, which would be difficult to debug.
|
||||
*
|
||||
* @param bytes the {@link ByteString} to be written
|
||||
* @param output the output to receive the bytes
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @param output the output to receive the bytes
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException {
|
||||
bytes.writeTo(output);
|
||||
|
@ -226,7 +226,7 @@ final class UnsafeUtil {
|
||||
}
|
||||
|
||||
static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length) {
|
||||
System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
|
||||
System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
|
||||
}
|
||||
|
||||
static byte getByte(long address) {
|
||||
@ -253,9 +253,7 @@ final class UnsafeUtil {
|
||||
MEMORY_ACCESSOR.putLong(address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
|
||||
*/
|
||||
/** Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}. */
|
||||
static long addressOffset(ByteBuffer buffer) {
|
||||
return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
|
||||
}
|
||||
@ -472,9 +470,9 @@ final class UnsafeUtil {
|
||||
public abstract void putLong(long address, long value);
|
||||
|
||||
public abstract Object getStaticObject(Field field);
|
||||
|
||||
|
||||
public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
|
||||
|
||||
|
||||
public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
|
||||
}
|
||||
|
||||
@ -553,12 +551,12 @@ final class UnsafeUtil {
|
||||
public void putDouble(Object target, long offset, double value) {
|
||||
unsafe.putDouble(target, offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
|
||||
unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
|
||||
unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
|
||||
|
@ -44,36 +44,31 @@ import static java.lang.Character.toCodePoint;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A set of low-level, high-performance static utility methods related
|
||||
* to the UTF-8 character encoding. This class has no dependencies
|
||||
* outside of the core JDK libraries.
|
||||
* A set of low-level, high-performance static utility methods related to the UTF-8 character
|
||||
* encoding. This class has no dependencies outside of the core JDK libraries.
|
||||
*
|
||||
* <p>There are several variants of UTF-8. The one implemented by
|
||||
* this class is the restricted definition of UTF-8 introduced in
|
||||
* Unicode 3.1, which mandates the rejection of "overlong" byte
|
||||
* sequences as well as rejection of 3-byte surrogate codepoint byte
|
||||
* sequences. Note that the UTF-8 decoder included in Oracle's JDK
|
||||
* has been modified to also reject "overlong" byte sequences, but (as
|
||||
* of 2011) still accepts 3-byte surrogate codepoint byte sequences.
|
||||
* <p>There are several variants of UTF-8. The one implemented by this class is the restricted
|
||||
* definition of UTF-8 introduced in Unicode 3.1, which mandates the rejection of "overlong" byte
|
||||
* sequences as well as rejection of 3-byte surrogate codepoint byte sequences. Note that the UTF-8
|
||||
* decoder included in Oracle's JDK has been modified to also reject "overlong" byte sequences, but
|
||||
* (as of 2011) still accepts 3-byte surrogate codepoint byte sequences.
|
||||
*
|
||||
* <p>The byte sequences considered valid by this class are exactly
|
||||
* those that can be roundtrip converted to Strings and back to bytes
|
||||
* using the UTF-8 charset, without loss: <pre> {@code
|
||||
* <p>The byte sequences considered valid by this class are exactly those that can be roundtrip
|
||||
* converted to Strings and back to bytes using the UTF-8 charset, without loss:
|
||||
*
|
||||
* <pre>{@code
|
||||
* Arrays.equals(bytes, new String(bytes, Internal.UTF_8).getBytes(Internal.UTF_8))
|
||||
* }</pre>
|
||||
*
|
||||
* <p>See the Unicode Standard,</br>
|
||||
* Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
|
||||
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
|
||||
* <p>See the Unicode Standard,</br> Table 3-6. <em>UTF-8 Bit Distribution</em>,</br> Table 3-7.
|
||||
* <em>Well Formed UTF-8 Byte Sequences</em>.
|
||||
*
|
||||
* <p>This class supports decoding of partial byte sequences, so that the
|
||||
* bytes in a complete UTF-8 byte sequences can be stored in multiple
|
||||
* segments. Methods typically return {@link #MALFORMED} if the partial
|
||||
* byte sequence is definitely not well-formed, {@link #COMPLETE} if it is
|
||||
* well-formed in the absence of additional input, or if the byte sequence
|
||||
* apparently terminated in the middle of a character, an opaque integer
|
||||
* "state" value containing enough information to decode the character when
|
||||
* passed to a subsequent invocation of a partial decoding method.
|
||||
* <p>This class supports decoding of partial byte sequences, so that the bytes in a complete UTF-8
|
||||
* byte sequences can be stored in multiple segments. Methods typically return {@link #MALFORMED} if
|
||||
* the partial byte sequence is definitely not well-formed, {@link #COMPLETE} if it is well-formed
|
||||
* in the absence of additional input, or if the byte sequence apparently terminated in the middle
|
||||
* of a character, an opaque integer "state" value containing enough information to decode the
|
||||
* character when passed to a subsequent invocation of a partial decoding method.
|
||||
*
|
||||
* @author martinrb@google.com (Martin Buchholz)
|
||||
*/
|
||||
@ -98,31 +93,28 @@ final class Utf8 {
|
||||
|
||||
/**
|
||||
* Maximum number of bytes per Java UTF-16 char in UTF-8.
|
||||
*
|
||||
* @see java.nio.charset.CharsetEncoder#maxBytesPerChar()
|
||||
*/
|
||||
static final int MAX_BYTES_PER_CHAR = 3;
|
||||
|
||||
/**
|
||||
* State value indicating that the byte sequence is well-formed and
|
||||
* complete (no further bytes are needed to complete a character).
|
||||
* State value indicating that the byte sequence is well-formed and complete (no further bytes are
|
||||
* needed to complete a character).
|
||||
*/
|
||||
public static final int COMPLETE = 0;
|
||||
|
||||
/**
|
||||
* State value indicating that the byte sequence is definitely not
|
||||
* well-formed.
|
||||
*/
|
||||
/** State value indicating that the byte sequence is definitely not well-formed. */
|
||||
public static final int MALFORMED = -1;
|
||||
|
||||
/**
|
||||
* Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length
|
||||
* above which to employ an optimized algorithm for counting ASCII characters. The reason for this
|
||||
* threshold is that for small strings, the optimization may not be beneficial or may even
|
||||
* negatively impact performance since it requires additional logic to avoid unaligned reads
|
||||
* (when calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial
|
||||
* offset is unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()}
|
||||
* which provides a performance improvement that entirely subsumes the cost of the additional
|
||||
* logic.
|
||||
* negatively impact performance since it requires additional logic to avoid unaligned reads (when
|
||||
* calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial offset is
|
||||
* unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()} which
|
||||
* provides a performance improvement that entirely subsumes the cost of the additional logic.
|
||||
*/
|
||||
private static final int UNSAFE_COUNT_ASCII_THRESHOLD = 16;
|
||||
|
||||
@ -146,76 +138,69 @@ final class Utf8 {
|
||||
// are valid trailing bytes.
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given byte array is a well-formed
|
||||
* UTF-8 byte sequence.
|
||||
* Returns {@code true} if the given byte array is a well-formed UTF-8 byte sequence.
|
||||
*
|
||||
* <p>This is a convenience method, equivalent to a call to {@code
|
||||
* isValidUtf8(bytes, 0, bytes.length)}.
|
||||
* <p>This is a convenience method, equivalent to a call to {@code isValidUtf8(bytes, 0,
|
||||
* bytes.length)}.
|
||||
*/
|
||||
public static boolean isValidUtf8(byte[] bytes) {
|
||||
return processor.isValidUtf8(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given byte array slice is a
|
||||
* well-formed UTF-8 byte sequence. The range of bytes to be
|
||||
* checked extends from index {@code index}, inclusive, to {@code
|
||||
* limit}, exclusive.
|
||||
* Returns {@code true} if the given byte array slice is a well-formed UTF-8 byte sequence. The
|
||||
* range of bytes to be checked extends from index {@code index}, inclusive, to {@code limit},
|
||||
* exclusive.
|
||||
*
|
||||
* <p>This is a convenience method, equivalent to {@code
|
||||
* partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
|
||||
* <p>This is a convenience method, equivalent to {@code partialIsValidUtf8(bytes, index, limit)
|
||||
* == Utf8.COMPLETE}.
|
||||
*/
|
||||
public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
|
||||
return processor.isValidUtf8(bytes, index, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given byte array slice is a well-formed,
|
||||
* malformed, or incomplete UTF-8 byte sequence. The range of bytes
|
||||
* to be checked extends from index {@code index}, inclusive, to
|
||||
* Tells whether the given byte array slice is a well-formed, malformed, or incomplete UTF-8 byte
|
||||
* sequence. The range of bytes to be checked extends from index {@code index}, inclusive, to
|
||||
* {@code limit}, exclusive.
|
||||
*
|
||||
* @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
|
||||
* operation) or the value returned from a call to a partial decoding method
|
||||
* for the previous bytes
|
||||
*
|
||||
* @return {@link #MALFORMED} if the partial byte sequence is
|
||||
* definitely not well-formed, {@link #COMPLETE} if it is well-formed
|
||||
* (no additional input needed), or if the byte sequence is
|
||||
* "incomplete", i.e. apparently terminated in the middle of a character,
|
||||
* an opaque integer "state" value containing enough information to
|
||||
* decode the character when passed to a subsequent invocation of a
|
||||
* partial decoding method.
|
||||
* @param state either {@link Utf8#COMPLETE} (if this is the initial decoding operation) or the
|
||||
* value returned from a call to a partial decoding method for the previous bytes
|
||||
* @return {@link #MALFORMED} if the partial byte sequence is definitely not well-formed, {@link
|
||||
* #COMPLETE} if it is well-formed (no additional input needed), or if the byte sequence is
|
||||
* "incomplete", i.e. apparently terminated in the middle of a character, an opaque integer
|
||||
* "state" value containing enough information to decode the character when passed to a
|
||||
* subsequent invocation of a partial decoding method.
|
||||
*/
|
||||
public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
|
||||
return processor.partialIsValidUtf8(state, bytes, index, limit);
|
||||
}
|
||||
|
||||
private static int incompleteStateFor(int byte1) {
|
||||
return (byte1 > (byte) 0xF4) ?
|
||||
MALFORMED : byte1;
|
||||
return (byte1 > (byte) 0xF4) ? MALFORMED : byte1;
|
||||
}
|
||||
|
||||
private static int incompleteStateFor(int byte1, int byte2) {
|
||||
return (byte1 > (byte) 0xF4 ||
|
||||
byte2 > (byte) 0xBF) ?
|
||||
MALFORMED : byte1 ^ (byte2 << 8);
|
||||
return (byte1 > (byte) 0xF4 || byte2 > (byte) 0xBF) ? MALFORMED : byte1 ^ (byte2 << 8);
|
||||
}
|
||||
|
||||
private static int incompleteStateFor(int byte1, int byte2, int byte3) {
|
||||
return (byte1 > (byte) 0xF4 ||
|
||||
byte2 > (byte) 0xBF ||
|
||||
byte3 > (byte) 0xBF) ?
|
||||
MALFORMED : byte1 ^ (byte2 << 8) ^ (byte3 << 16);
|
||||
return (byte1 > (byte) 0xF4 || byte2 > (byte) 0xBF || byte3 > (byte) 0xBF)
|
||||
? MALFORMED
|
||||
: byte1 ^ (byte2 << 8) ^ (byte3 << 16);
|
||||
}
|
||||
|
||||
private static int incompleteStateFor(byte[] bytes, int index, int limit) {
|
||||
int byte1 = bytes[index - 1];
|
||||
switch (limit - index) {
|
||||
case 0: return incompleteStateFor(byte1);
|
||||
case 1: return incompleteStateFor(byte1, bytes[index]);
|
||||
case 2: return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
|
||||
default: throw new AssertionError();
|
||||
case 0:
|
||||
return incompleteStateFor(byte1);
|
||||
case 1:
|
||||
return incompleteStateFor(byte1, bytes[index]);
|
||||
case 2:
|
||||
return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +221,7 @@ final class Utf8 {
|
||||
// These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw
|
||||
// a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
|
||||
// fallback to more lenient behavior.
|
||||
|
||||
|
||||
static class UnpairedSurrogateException extends IllegalArgumentException {
|
||||
UnpairedSurrogateException(int index, int length) {
|
||||
super("Unpaired surrogate at index " + index + " of " + length);
|
||||
@ -244,9 +229,9 @@ final class Utf8 {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
|
||||
* this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
|
||||
* both time and space.
|
||||
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string, this
|
||||
* method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in both
|
||||
* time and space.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
@ -266,7 +251,7 @@ final class Utf8 {
|
||||
for (; i < utf16Length; i++) {
|
||||
char c = sequence.charAt(i);
|
||||
if (c < 0x800) {
|
||||
utf8Length += ((0x7f - c) >>> 31); // branch free!
|
||||
utf8Length += ((0x7f - c) >>> 31); // branch free!
|
||||
} else {
|
||||
utf8Length += encodedLengthGeneral(sequence, i);
|
||||
break;
|
||||
@ -275,8 +260,8 @@ final class Utf8 {
|
||||
|
||||
if (utf8Length < utf16Length) {
|
||||
// Necessary and sufficient condition for overflow because of maximum 3x expansion
|
||||
throw new IllegalArgumentException("UTF-8 length does not fit in int: "
|
||||
+ (utf8Length + (1L << 32)));
|
||||
throw new IllegalArgumentException(
|
||||
"UTF-8 length does not fit in int: " + (utf8Length + (1L << 32)));
|
||||
}
|
||||
return utf8Length;
|
||||
}
|
||||
@ -370,15 +355,15 @@ final class Utf8 {
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts (approximately) the number of consecutive ASCII characters in the given buffer.
|
||||
* The byte order of the {@link ByteBuffer} does not matter, so performance can be improved if
|
||||
* native byte order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}).
|
||||
* Counts (approximately) the number of consecutive ASCII characters in the given buffer. The byte
|
||||
* order of the {@link ByteBuffer} does not matter, so performance can be improved if native byte
|
||||
* order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}).
|
||||
*
|
||||
* @param buffer the buffer to be scanned for ASCII chars
|
||||
* @param index the starting index of the scan
|
||||
* @param limit the limit within buffer for the scan
|
||||
* @return the number of ASCII characters found. The stopping position will be at or
|
||||
* before the first non-ASCII byte.
|
||||
* @return the number of ASCII characters found. The stopping position will be at or before the
|
||||
* first non-ASCII byte.
|
||||
*/
|
||||
private static int estimateConsecutiveAscii(ByteBuffer buffer, int index, int limit) {
|
||||
int i = index;
|
||||
@ -390,52 +375,43 @@ final class Utf8 {
|
||||
return i - index;
|
||||
}
|
||||
|
||||
/**
|
||||
* A processor of UTF-8 strings, providing methods for checking validity and encoding.
|
||||
*/
|
||||
/** A processor of UTF-8 strings, providing methods for checking validity and encoding. */
|
||||
// TODO(nathanmittler): Add support for Memory/MemoryBlock on Android.
|
||||
abstract static class Processor {
|
||||
/**
|
||||
* Returns {@code true} if the given byte array slice is a
|
||||
* well-formed UTF-8 byte sequence. The range of bytes to be
|
||||
* checked extends from index {@code index}, inclusive, to {@code
|
||||
* limit}, exclusive.
|
||||
* Returns {@code true} if the given byte array slice is a well-formed UTF-8 byte sequence. The
|
||||
* range of bytes to be checked extends from index {@code index}, inclusive, to {@code limit},
|
||||
* exclusive.
|
||||
*
|
||||
* <p>This is a convenience method, equivalent to {@code
|
||||
* partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
|
||||
* <p>This is a convenience method, equivalent to {@code partialIsValidUtf8(bytes, index, limit)
|
||||
* == Utf8.COMPLETE}.
|
||||
*/
|
||||
final boolean isValidUtf8(byte[] bytes, int index, int limit) {
|
||||
return partialIsValidUtf8(COMPLETE, bytes, index, limit) == COMPLETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given byte array slice is a well-formed,
|
||||
* malformed, or incomplete UTF-8 byte sequence. The range of bytes
|
||||
* to be checked extends from index {@code index}, inclusive, to
|
||||
* {@code limit}, exclusive.
|
||||
* Tells whether the given byte array slice is a well-formed, malformed, or incomplete UTF-8
|
||||
* byte sequence. The range of bytes to be checked extends from index {@code index}, inclusive,
|
||||
* to {@code limit}, exclusive.
|
||||
*
|
||||
* @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
|
||||
* operation) or the value returned from a call to a partial decoding method
|
||||
* for the previous bytes
|
||||
*
|
||||
* @return {@link #MALFORMED} if the partial byte sequence is
|
||||
* definitely not well-formed, {@link #COMPLETE} if it is well-formed
|
||||
* (no additional input needed), or if the byte sequence is
|
||||
* "incomplete", i.e. apparently terminated in the middle of a character,
|
||||
* an opaque integer "state" value containing enough information to
|
||||
* decode the character when passed to a subsequent invocation of a
|
||||
* partial decoding method.
|
||||
* @param state either {@link Utf8#COMPLETE} (if this is the initial decoding operation) or the
|
||||
* value returned from a call to a partial decoding method for the previous bytes
|
||||
* @return {@link #MALFORMED} if the partial byte sequence is definitely not well-formed, {@link
|
||||
* #COMPLETE} if it is well-formed (no additional input needed), or if the byte sequence is
|
||||
* "incomplete", i.e. apparently terminated in the middle of a character, an opaque integer
|
||||
* "state" value containing enough information to decode the character when passed to a
|
||||
* subsequent invocation of a partial decoding method.
|
||||
*/
|
||||
abstract int partialIsValidUtf8(int state, byte[] bytes, int index, int limit);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given portion of the {@link ByteBuffer} is a
|
||||
* well-formed UTF-8 byte sequence. The range of bytes to be
|
||||
* checked extends from index {@code index}, inclusive, to {@code
|
||||
* limit}, exclusive.
|
||||
* Returns {@code true} if the given portion of the {@link ByteBuffer} is a well-formed UTF-8
|
||||
* byte sequence. The range of bytes to be checked extends from index {@code index}, inclusive,
|
||||
* to {@code limit}, exclusive.
|
||||
*
|
||||
* <p>This is a convenience method, equivalent to {@code
|
||||
* partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
|
||||
* <p>This is a convenience method, equivalent to {@code partialIsValidUtf8(bytes, index, limit)
|
||||
* == Utf8.COMPLETE}.
|
||||
*/
|
||||
final boolean isValidUtf8(ByteBuffer buffer, int index, int limit) {
|
||||
return partialIsValidUtf8(COMPLETE, buffer, index, limit) == COMPLETE;
|
||||
@ -452,22 +428,20 @@ final class Utf8 {
|
||||
if (buffer.hasArray()) {
|
||||
final int offset = buffer.arrayOffset();
|
||||
return partialIsValidUtf8(state, buffer.array(), offset + index, offset + limit);
|
||||
} else if (buffer.isDirect()){
|
||||
} else if (buffer.isDirect()) {
|
||||
return partialIsValidUtf8Direct(state, buffer, index, limit);
|
||||
}
|
||||
return partialIsValidUtf8Default(state, buffer, index, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs validation for direct {@link ByteBuffer} instances.
|
||||
*/
|
||||
/** Performs validation for direct {@link ByteBuffer} instances. */
|
||||
abstract int partialIsValidUtf8Direct(
|
||||
final int state, final ByteBuffer buffer, int index, final int limit);
|
||||
|
||||
/**
|
||||
* Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
|
||||
* than potentially faster approaches. This first completes validation for the current
|
||||
* character (provided by {@code state}) and then finishes validation for the sequence.
|
||||
* than potentially faster approaches. This first completes validation for the current character
|
||||
* (provided by {@code state}) and then finishes validation for the sequence.
|
||||
*/
|
||||
final int partialIsValidUtf8Default(
|
||||
final int state, final ByteBuffer buffer, int index, final int limit) {
|
||||
@ -566,7 +540,7 @@ final class Utf8 {
|
||||
private static int partialIsValidUtf8(final ByteBuffer buffer, int index, final int limit) {
|
||||
index += estimateConsecutiveAscii(buffer, index, limit);
|
||||
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
// Optimize for interior runs of ASCII bytes.
|
||||
// TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
|
||||
// Maybe after seeing a few in a row that are ASCII, go back to fast mode?
|
||||
@ -658,15 +632,13 @@ final class Utf8 {
|
||||
return decodeUtf8Default(buffer, index, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes direct {@link ByteBuffer} instances into {@link String}.
|
||||
*/
|
||||
/** Decodes direct {@link ByteBuffer} instances into {@link String}. */
|
||||
abstract String decodeUtf8Direct(ByteBuffer buffer, int index, int size)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuffer} instances using the {@link ByteBuffer} API rather than
|
||||
* potentially faster approaches.
|
||||
* Decodes {@link ByteBuffer} instances using the {@link ByteBuffer} API rather than potentially
|
||||
* faster approaches.
|
||||
*/
|
||||
final String decodeUtf8Default(ByteBuffer buffer, int index, int size)
|
||||
throws InvalidProtocolBufferException {
|
||||
@ -747,21 +719,22 @@ final class Utf8 {
|
||||
/**
|
||||
* Encodes an input character sequence ({@code in}) to UTF-8 in the target array ({@code out}).
|
||||
* For a string, this method is similar to
|
||||
*
|
||||
* <pre>{@code
|
||||
* byte[] a = string.getBytes(UTF_8);
|
||||
* System.arraycopy(a, 0, bytes, offset, a.length);
|
||||
* return offset + a.length;
|
||||
* }</pre>
|
||||
*
|
||||
* but is more efficient in both time and space. One key difference is that this method
|
||||
* requires paired surrogates, and therefore does not support chunking.
|
||||
* While {@code String.getBytes(UTF_8)} replaces unpaired surrogates with the default
|
||||
* replacement character, this method throws {@link UnpairedSurrogateException}.
|
||||
* but is more efficient in both time and space. One key difference is that this method requires
|
||||
* paired surrogates, and therefore does not support chunking. While {@code
|
||||
* String.getBytes(UTF_8)} replaces unpaired surrogates with the default replacement character,
|
||||
* this method throws {@link UnpairedSurrogateException}.
|
||||
*
|
||||
* <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
|
||||
* compute the exact amount needed, or leave room for
|
||||
* {@code Utf8.MAX_BYTES_PER_CHAR * sequence.length()}, which is the largest possible number
|
||||
* of bytes that any input can be encoded to.
|
||||
* compute the exact amount needed, or leave room for {@code Utf8.MAX_BYTES_PER_CHAR *
|
||||
* sequence.length()}, which is the largest possible number of bytes that any input can be
|
||||
* encoded to.
|
||||
*
|
||||
* @param in the input character sequence to be encoded
|
||||
* @param out the target array
|
||||
@ -778,26 +751,24 @@ final class Utf8 {
|
||||
/**
|
||||
* Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}).
|
||||
* Upon returning from this method, the {@code out} position will point to the position after
|
||||
* the last encoded byte. This method requires paired surrogates, and therefore does not
|
||||
* support chunking.
|
||||
* the last encoded byte. This method requires paired surrogates, and therefore does not support
|
||||
* chunking.
|
||||
*
|
||||
* <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
|
||||
* compute the exact amount needed, or leave room for
|
||||
* {@code Utf8.MAX_BYTES_PER_CHAR * in.length()}, which is the largest possible number
|
||||
* of bytes that any input can be encoded to.
|
||||
* compute the exact amount needed, or leave room for {@code Utf8.MAX_BYTES_PER_CHAR *
|
||||
* in.length()}, which is the largest possible number of bytes that any input can be encoded to.
|
||||
*
|
||||
* @param in the source character sequence to be encoded
|
||||
* @param out the target buffer
|
||||
* @throws UnpairedSurrogateException if {@code in} contains ill-formed UTF-16 (unpaired
|
||||
* surrogates)
|
||||
* @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than
|
||||
* {@code out.remaining()}
|
||||
* @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than {@code
|
||||
* out.remaining()}
|
||||
*/
|
||||
final void encodeUtf8(CharSequence in, ByteBuffer out) {
|
||||
if (out.hasArray()) {
|
||||
final int offset = out.arrayOffset();
|
||||
int endIndex =
|
||||
Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
|
||||
int endIndex = Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
|
||||
out.position(endIndex - offset);
|
||||
} else if (out.isDirect()) {
|
||||
encodeUtf8Direct(in, out);
|
||||
@ -806,9 +777,7 @@ final class Utf8 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the input character sequence to a direct {@link ByteBuffer} instance.
|
||||
*/
|
||||
/** Encodes the input character sequence to a direct {@link ByteBuffer} instance. */
|
||||
abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out);
|
||||
|
||||
/**
|
||||
@ -887,9 +856,7 @@ final class Utf8 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods.
|
||||
*/
|
||||
/** {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods. */
|
||||
static final class SafeProcessor extends Processor {
|
||||
@Override
|
||||
int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
|
||||
@ -901,7 +868,7 @@ final class Utf8 {
|
||||
//
|
||||
// We expect such "straddler characters" to be rare.
|
||||
|
||||
if (index >= limit) { // No bytes? No progress.
|
||||
if (index >= limit) { // No bytes? No progress.
|
||||
return state;
|
||||
}
|
||||
int byte1 = (byte) state;
|
||||
@ -1098,8 +1065,7 @@ final class Utf8 {
|
||||
// Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
||||
// four UTF-8 bytes
|
||||
final char low;
|
||||
if (i + 1 == in.length()
|
||||
|| !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
|
||||
if (i + 1 == in.length() || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
|
||||
throw new UnpairedSurrogateException((i - 1), utf16Length);
|
||||
}
|
||||
int codePoint = Character.toCodePoint(c, low);
|
||||
@ -1111,8 +1077,7 @@ final class Utf8 {
|
||||
// If we are surrogates and we're not a surrogate pair, always throw an
|
||||
// UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
|
||||
if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
|
||||
&& (i + 1 == in.length()
|
||||
|| !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
|
||||
&& (i + 1 == in.length() || !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
|
||||
throw new UnpairedSurrogateException(i, utf16Length);
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
|
||||
@ -1138,7 +1103,7 @@ final class Utf8 {
|
||||
}
|
||||
|
||||
private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) {
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
int byte1, byte2;
|
||||
|
||||
// Optimize for interior runs of ASCII bytes.
|
||||
@ -1158,8 +1123,7 @@ final class Utf8 {
|
||||
|
||||
// Simultaneously checks for illegal trailing-byte in
|
||||
// leading position and overlong 2-byte form.
|
||||
if (byte1 < (byte) 0xC2
|
||||
|| bytes[index++] > (byte) 0xBF) {
|
||||
if (byte1 < (byte) 0xC2 || bytes[index++] > (byte) 0xBF) {
|
||||
return MALFORMED;
|
||||
}
|
||||
} else if (byte1 < (byte) 0xF0) {
|
||||
@ -1180,7 +1144,7 @@ final class Utf8 {
|
||||
} else {
|
||||
// four-byte form
|
||||
|
||||
if (index >= limit - 2) { // incomplete sequence
|
||||
if (index >= limit - 2) { // incomplete sequence
|
||||
return incompleteStateFor(bytes, index, limit);
|
||||
}
|
||||
if ((byte2 = bytes[index++]) > (byte) 0xBF
|
||||
@ -1200,13 +1164,9 @@ final class Utf8 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
|
||||
*/
|
||||
/** {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance. */
|
||||
static final class UnsafeProcessor extends Processor {
|
||||
/**
|
||||
* Indicates whether or not all required unsafe operations are supported on this platform.
|
||||
*/
|
||||
/** Indicates whether or not all required unsafe operations are supported on this platform. */
|
||||
static boolean isAvailable() {
|
||||
return hasUnsafeArrayOperations() && hasUnsafeByteBufferOperations();
|
||||
}
|
||||
@ -1228,7 +1188,7 @@ final class Utf8 {
|
||||
//
|
||||
// We expect such "straddler characters" to be rare.
|
||||
|
||||
if (offset >= offsetLimit) { // No bytes? No progress.
|
||||
if (offset >= offsetLimit) { // No bytes? No progress.
|
||||
return state;
|
||||
}
|
||||
int byte1 = (byte) state;
|
||||
@ -1685,8 +1645,8 @@ final class Utf8 {
|
||||
* @param bytes the array containing the character sequence
|
||||
* @param offset the offset position of the index (same as index + arrayBaseOffset)
|
||||
* @param maxChars the maximum number of characters to count
|
||||
* @return the number of ASCII characters found. The stopping position will be at or
|
||||
* before the first non-ASCII byte.
|
||||
* @return the number of ASCII characters found. The stopping position will be at or before the
|
||||
* first non-ASCII byte.
|
||||
*/
|
||||
private static int unsafeEstimateConsecutiveAscii(
|
||||
byte[] bytes, long offset, final int maxChars) {
|
||||
@ -1728,24 +1688,24 @@ final class Utf8 {
|
||||
// To speed things up further, we're reading longs instead of bytes so we use a mask to
|
||||
// determine if any byte in the current long is non-ASCII.
|
||||
remaining -= unaligned;
|
||||
for (; remaining >= 8 && (UnsafeUtil.getLong(address) & ASCII_MASK_LONG) == 0;
|
||||
for (;
|
||||
remaining >= 8 && (UnsafeUtil.getLong(address) & ASCII_MASK_LONG) == 0;
|
||||
address += 8, remaining -= 8) {}
|
||||
return maxChars - remaining;
|
||||
}
|
||||
|
||||
private static int partialIsValidUtf8(final byte[] bytes, long offset, int remaining) {
|
||||
// Skip past ASCII characters as quickly as possible.
|
||||
// Skip past ASCII characters as quickly as possible.
|
||||
final int skipped = unsafeEstimateConsecutiveAscii(bytes, offset, remaining);
|
||||
remaining -= skipped;
|
||||
offset += skipped;
|
||||
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
// Optimize for interior runs of ASCII bytes.
|
||||
// TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
|
||||
// Maybe after seeing a few in a row that are ASCII, go back to fast mode?
|
||||
int byte1 = 0;
|
||||
for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(bytes, offset++)) >= 0; --remaining) {
|
||||
}
|
||||
for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(bytes, offset++)) >= 0; --remaining) {}
|
||||
if (remaining == 0) {
|
||||
return COMPLETE;
|
||||
}
|
||||
@ -1762,8 +1722,7 @@ final class Utf8 {
|
||||
|
||||
// Simultaneously checks for illegal trailing-byte in
|
||||
// leading position and overlong 2-byte form.
|
||||
if (byte1 < (byte) 0xC2
|
||||
|| UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
|
||||
if (byte1 < (byte) 0xC2 || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
|
||||
return MALFORMED;
|
||||
}
|
||||
} else if (byte1 < (byte) 0xF0) {
|
||||
@ -1815,13 +1774,12 @@ final class Utf8 {
|
||||
address += skipped;
|
||||
remaining -= skipped;
|
||||
|
||||
for (;;) {
|
||||
for (; ; ) {
|
||||
// Optimize for interior runs of ASCII bytes.
|
||||
// TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
|
||||
// Maybe after seeing a few in a row that are ASCII, go back to fast mode?
|
||||
int byte1 = 0;
|
||||
for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(address++)) >= 0; --remaining) {
|
||||
}
|
||||
for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(address++)) >= 0; --remaining) {}
|
||||
if (remaining == 0) {
|
||||
return COMPLETE;
|
||||
}
|
||||
@ -1886,40 +1844,32 @@ final class Utf8 {
|
||||
}
|
||||
}
|
||||
|
||||
private static int unsafeIncompleteStateFor(byte[] bytes, int byte1, long offset,
|
||||
int remaining) {
|
||||
private static int unsafeIncompleteStateFor(
|
||||
byte[] bytes, int byte1, long offset, int remaining) {
|
||||
switch (remaining) {
|
||||
case 0: {
|
||||
case 0:
|
||||
return incompleteStateFor(byte1);
|
||||
}
|
||||
case 1: {
|
||||
case 1:
|
||||
return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset));
|
||||
}
|
||||
case 2: {
|
||||
return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset),
|
||||
UnsafeUtil.getByte(bytes, offset + 1));
|
||||
}
|
||||
default: {
|
||||
case 2:
|
||||
return incompleteStateFor(
|
||||
byte1, UnsafeUtil.getByte(bytes, offset), UnsafeUtil.getByte(bytes, offset + 1));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int unsafeIncompleteStateFor(long address, final int byte1, int remaining) {
|
||||
switch (remaining) {
|
||||
case 0: {
|
||||
case 0:
|
||||
return incompleteStateFor(byte1);
|
||||
}
|
||||
case 1: {
|
||||
case 1:
|
||||
return incompleteStateFor(byte1, UnsafeUtil.getByte(address));
|
||||
}
|
||||
case 2: {
|
||||
return incompleteStateFor(byte1, UnsafeUtil.getByte(address),
|
||||
UnsafeUtil.getByte(address + 1));
|
||||
}
|
||||
default: {
|
||||
case 2:
|
||||
return incompleteStateFor(
|
||||
byte1, UnsafeUtil.getByte(address), UnsafeUtil.getByte(address + 1));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1931,23 +1881,17 @@ final class Utf8 {
|
||||
*/
|
||||
private static class DecodeUtil {
|
||||
|
||||
/**
|
||||
* Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
|
||||
*/
|
||||
/** Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'. */
|
||||
private static boolean isOneByte(byte b) {
|
||||
return b >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is a two-byte codepoint with the form '10XXXXXX'.
|
||||
*/
|
||||
/** Returns whether this is a two-byte codepoint with the form '10XXXXXX'. */
|
||||
private static boolean isTwoBytes(byte b) {
|
||||
return b < (byte) 0xE0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is a three-byte codepoint with the form '110XXXXX'.
|
||||
*/
|
||||
/** Returns whether this is a three-byte codepoint with the form '110XXXXX'. */
|
||||
private static boolean isThreeBytes(byte b) {
|
||||
return b < (byte) 0xF0;
|
||||
}
|
||||
@ -1956,13 +1900,11 @@ final class Utf8 {
|
||||
resultArr[resultPos] = (char) byte1;
|
||||
}
|
||||
|
||||
private static void handleTwoBytes(
|
||||
byte byte1, byte byte2, char[] resultArr, int resultPos)
|
||||
private static void handleTwoBytes(byte byte1, byte byte2, char[] resultArr, int resultPos)
|
||||
throws InvalidProtocolBufferException {
|
||||
// Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
|
||||
// overlong 2-byte, '11000001'.
|
||||
if (byte1 < (byte) 0xC2
|
||||
|| isNotTrailingByte(byte2)) {
|
||||
if (byte1 < (byte) 0xC2 || isNotTrailingByte(byte2)) {
|
||||
throw InvalidProtocolBufferException.invalidUtf8();
|
||||
}
|
||||
resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));
|
||||
@ -1979,13 +1921,14 @@ final class Utf8 {
|
||||
|| isNotTrailingByte(byte3)) {
|
||||
throw InvalidProtocolBufferException.invalidUtf8();
|
||||
}
|
||||
resultArr[resultPos] = (char)
|
||||
(((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
|
||||
resultArr[resultPos] =
|
||||
(char)
|
||||
(((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
|
||||
}
|
||||
|
||||
private static void handleFourBytes(
|
||||
byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr, int resultPos)
|
||||
throws InvalidProtocolBufferException{
|
||||
throws InvalidProtocolBufferException {
|
||||
if (isNotTrailingByte(byte2)
|
||||
// Check that 1 <= plane <= 16. Tricky optimized form of:
|
||||
// valid 4-byte leading byte?
|
||||
@ -1999,31 +1942,28 @@ final class Utf8 {
|
||||
|| isNotTrailingByte(byte4)) {
|
||||
throw InvalidProtocolBufferException.invalidUtf8();
|
||||
}
|
||||
int codepoint = ((byte1 & 0x07) << 18)
|
||||
| (trailingByteValue(byte2) << 12)
|
||||
| (trailingByteValue(byte3) << 6)
|
||||
| trailingByteValue(byte4);
|
||||
int codepoint =
|
||||
((byte1 & 0x07) << 18)
|
||||
| (trailingByteValue(byte2) << 12)
|
||||
| (trailingByteValue(byte3) << 6)
|
||||
| trailingByteValue(byte4);
|
||||
resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);
|
||||
resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
|
||||
*/
|
||||
/** Returns whether the byte is not a valid continuation of the form '10XXXXXX'. */
|
||||
private static boolean isNotTrailingByte(byte b) {
|
||||
return b > (byte) 0xBF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual value of the trailing byte (removes the prefix '10') for composition.
|
||||
*/
|
||||
/** Returns the actual value of the trailing byte (removes the prefix '10') for composition. */
|
||||
private static int trailingByteValue(byte b) {
|
||||
return b & 0x3F;
|
||||
}
|
||||
|
||||
private static char highSurrogate(int codePoint) {
|
||||
return (char) ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))
|
||||
+ (codePoint >>> 10));
|
||||
return (char)
|
||||
((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)) + (codePoint >>> 10));
|
||||
}
|
||||
|
||||
private static char lowSurrogate(int codePoint) {
|
||||
|
@ -33,13 +33,12 @@ package com.google.protobuf;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class is used internally by the Protocol Buffer library and generated
|
||||
* message implementations. It is public only because those generated messages
|
||||
* do not reside in the {@code protobuf} package. Others should not use this
|
||||
* class directly.
|
||||
* This class is used internally by the Protocol Buffer library and generated message
|
||||
* implementations. It is public only because those generated messages do not reside in the {@code
|
||||
* protobuf} package. Others should not use this class directly.
|
||||
*
|
||||
* This class contains constants and helper functions useful for dealing with
|
||||
* the Protocol Buffer wire format.
|
||||
* <p>This class contains constants and helper functions useful for dealing with the Protocol Buffer
|
||||
* wire format.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@ -53,12 +52,12 @@ public final class WireFormat {
|
||||
static final int MAX_VARINT64_SIZE = 10;
|
||||
static final int MAX_VARINT_SIZE = 10;
|
||||
|
||||
public static final int WIRETYPE_VARINT = 0;
|
||||
public static final int WIRETYPE_FIXED64 = 1;
|
||||
public static final int WIRETYPE_VARINT = 0;
|
||||
public static final int WIRETYPE_FIXED64 = 1;
|
||||
public static final int WIRETYPE_LENGTH_DELIMITED = 2;
|
||||
public static final int WIRETYPE_START_GROUP = 3;
|
||||
public static final int WIRETYPE_END_GROUP = 4;
|
||||
public static final int WIRETYPE_FIXED32 = 5;
|
||||
public static final int WIRETYPE_START_GROUP = 3;
|
||||
public static final int WIRETYPE_END_GROUP = 4;
|
||||
public static final int WIRETYPE_FIXED32 = 5;
|
||||
|
||||
static final int TAG_TYPE_BITS = 3;
|
||||
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
|
||||
@ -79,8 +78,8 @@ public final class WireFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
|
||||
* only here to support the lite runtime and should not be used by users.
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is only here to support
|
||||
* the lite runtime and should not be used by users.
|
||||
*/
|
||||
public enum JavaType {
|
||||
INT(0),
|
||||
@ -97,10 +96,7 @@ public final class WireFormat {
|
||||
this.defaultDefault = defaultDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default default value for fields of this type, if it's a primitive
|
||||
* type.
|
||||
*/
|
||||
/** The default default value for fields of this type, if it's a primitive type. */
|
||||
Object getDefaultDefault() {
|
||||
return defaultDefault;
|
||||
}
|
||||
@ -109,44 +105,48 @@ public final class WireFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
|
||||
* only here to support the lite runtime and should not be used by users.
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is only here to support the
|
||||
* lite runtime and should not be used by users.
|
||||
*/
|
||||
public enum FieldType {
|
||||
DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
|
||||
FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
|
||||
INT64 (JavaType.LONG , WIRETYPE_VARINT ),
|
||||
UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
|
||||
INT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
|
||||
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
|
||||
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
|
||||
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) {
|
||||
DOUBLE(JavaType.DOUBLE, WIRETYPE_FIXED64),
|
||||
FLOAT(JavaType.FLOAT, WIRETYPE_FIXED32),
|
||||
INT64(JavaType.LONG, WIRETYPE_VARINT),
|
||||
UINT64(JavaType.LONG, WIRETYPE_VARINT),
|
||||
INT32(JavaType.INT, WIRETYPE_VARINT),
|
||||
FIXED64(JavaType.LONG, WIRETYPE_FIXED64),
|
||||
FIXED32(JavaType.INT, WIRETYPE_FIXED32),
|
||||
BOOL(JavaType.BOOLEAN, WIRETYPE_VARINT),
|
||||
STRING(JavaType.STRING, WIRETYPE_LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean isPackable() {
|
||||
return false; }
|
||||
return false;
|
||||
}
|
||||
},
|
||||
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) {
|
||||
GROUP(JavaType.MESSAGE, WIRETYPE_START_GROUP) {
|
||||
@Override
|
||||
public boolean isPackable() {
|
||||
return false; }
|
||||
return false;
|
||||
}
|
||||
},
|
||||
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) {
|
||||
MESSAGE(JavaType.MESSAGE, WIRETYPE_LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean isPackable() {
|
||||
return false; }
|
||||
return false;
|
||||
}
|
||||
},
|
||||
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
|
||||
BYTES(JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean isPackable() {
|
||||
return false; }
|
||||
return false;
|
||||
}
|
||||
},
|
||||
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
|
||||
SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
|
||||
SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
|
||||
SINT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
SINT64 (JavaType.LONG , WIRETYPE_VARINT );
|
||||
UINT32(JavaType.INT, WIRETYPE_VARINT),
|
||||
ENUM(JavaType.ENUM, WIRETYPE_VARINT),
|
||||
SFIXED32(JavaType.INT, WIRETYPE_FIXED32),
|
||||
SFIXED64(JavaType.LONG, WIRETYPE_FIXED64),
|
||||
SINT32(JavaType.INT, WIRETYPE_VARINT),
|
||||
SINT64(JavaType.LONG, WIRETYPE_VARINT);
|
||||
|
||||
FieldType(final JavaType javaType, final int wireType) {
|
||||
this.javaType = javaType;
|
||||
@ -156,30 +156,34 @@ public final class WireFormat {
|
||||
private final JavaType javaType;
|
||||
private final int wireType;
|
||||
|
||||
public JavaType getJavaType() { return javaType; }
|
||||
public int getWireType() { return wireType; }
|
||||
public JavaType getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
public boolean isPackable() { return true; }
|
||||
public int getWireType() {
|
||||
return wireType;
|
||||
}
|
||||
|
||||
public boolean isPackable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Field numbers for fields in MessageSet wire format.
|
||||
static final int MESSAGE_SET_ITEM = 1;
|
||||
static final int MESSAGE_SET_ITEM = 1;
|
||||
static final int MESSAGE_SET_TYPE_ID = 2;
|
||||
static final int MESSAGE_SET_MESSAGE = 3;
|
||||
|
||||
// Tag numbers.
|
||||
static final int MESSAGE_SET_ITEM_TAG =
|
||||
makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
|
||||
static final int MESSAGE_SET_ITEM_END_TAG =
|
||||
makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
|
||||
static final int MESSAGE_SET_TYPE_ID_TAG =
|
||||
makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
|
||||
static final int MESSAGE_SET_ITEM_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
|
||||
static final int MESSAGE_SET_ITEM_END_TAG = makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
|
||||
static final int MESSAGE_SET_TYPE_ID_TAG = makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
|
||||
static final int MESSAGE_SET_MESSAGE_TAG =
|
||||
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
|
||||
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
/**
|
||||
* Validation level for handling incoming string field data which potentially
|
||||
* contain non-UTF8 bytes.
|
||||
* Validation level for handling incoming string field data which potentially contain non-UTF8
|
||||
* bytes.
|
||||
*/
|
||||
enum Utf8Validation {
|
||||
/** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
|
||||
@ -209,54 +213,59 @@ public final class WireFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a field of any primitive type for immutable messages from a
|
||||
* CodedInputStream. Enums, groups, and embedded messages are not handled by
|
||||
* this method.
|
||||
* Read a field of any primitive type for immutable messages from a CodedInputStream. Enums,
|
||||
* groups, and embedded messages are not handled by this method.
|
||||
*
|
||||
* @param input The stream from which to read.
|
||||
* @param type Declared type of the field.
|
||||
* @param utf8Validation Different string UTF8 validation level for handling
|
||||
* string fields.
|
||||
* @return An object representing the field's value, of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
* @param utf8Validation Different string UTF8 validation level for handling string fields.
|
||||
* @return An object representing the field's value, of the exact type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
|
||||
*/
|
||||
static Object readPrimitiveField(
|
||||
CodedInputStream input,
|
||||
FieldType type,
|
||||
Utf8Validation utf8Validation) throws IOException {
|
||||
CodedInputStream input, FieldType type, Utf8Validation utf8Validation) throws IOException {
|
||||
switch (type) {
|
||||
case DOUBLE : return input.readDouble ();
|
||||
case FLOAT : return input.readFloat ();
|
||||
case INT64 : return input.readInt64 ();
|
||||
case UINT64 : return input.readUInt64 ();
|
||||
case INT32 : return input.readInt32 ();
|
||||
case FIXED64 : return input.readFixed64 ();
|
||||
case FIXED32 : return input.readFixed32 ();
|
||||
case BOOL : return input.readBool ();
|
||||
case BYTES : return input.readBytes ();
|
||||
case UINT32 : return input.readUInt32 ();
|
||||
case SFIXED32: return input.readSFixed32();
|
||||
case SFIXED64: return input.readSFixed64();
|
||||
case SINT32 : return input.readSInt32 ();
|
||||
case SINT64 : return input.readSInt64 ();
|
||||
case DOUBLE:
|
||||
return input.readDouble();
|
||||
case FLOAT:
|
||||
return input.readFloat();
|
||||
case INT64:
|
||||
return input.readInt64();
|
||||
case UINT64:
|
||||
return input.readUInt64();
|
||||
case INT32:
|
||||
return input.readInt32();
|
||||
case FIXED64:
|
||||
return input.readFixed64();
|
||||
case FIXED32:
|
||||
return input.readFixed32();
|
||||
case BOOL:
|
||||
return input.readBool();
|
||||
case BYTES:
|
||||
return input.readBytes();
|
||||
case UINT32:
|
||||
return input.readUInt32();
|
||||
case SFIXED32:
|
||||
return input.readSFixed32();
|
||||
case SFIXED64:
|
||||
return input.readSFixed64();
|
||||
case SINT32:
|
||||
return input.readSInt32();
|
||||
case SINT64:
|
||||
return input.readSInt64();
|
||||
|
||||
case STRING : return utf8Validation.readString(input);
|
||||
case STRING:
|
||||
return utf8Validation.readString(input);
|
||||
case GROUP:
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle nested groups.");
|
||||
throw new IllegalArgumentException("readPrimitiveField() cannot handle nested groups.");
|
||||
case MESSAGE:
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle embedded messages.");
|
||||
throw new IllegalArgumentException("readPrimitiveField() cannot handle embedded messages.");
|
||||
case ENUM:
|
||||
// We don't handle enums because we don't know what to do if the
|
||||
// value is not recognized.
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle enums.");
|
||||
throw new IllegalArgumentException("readPrimitiveField() cannot handle enums.");
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
"There is no way to get here, but the compiler thinks otherwise.");
|
||||
throw new RuntimeException("There is no way to get here, but the compiler thinks otherwise.");
|
||||
}
|
||||
}
|
||||
|
@ -53,10 +53,9 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class AbstractMessageTest extends TestCase {
|
||||
/**
|
||||
* Extends AbstractMessage and wraps some other message object. The methods
|
||||
* of the Message interface which aren't explicitly implemented by
|
||||
* AbstractMessage are forwarded to the wrapped object. This allows us to
|
||||
* test that AbstractMessage's implementations work even if the wrapped
|
||||
* Extends AbstractMessage and wraps some other message object. The methods of the Message
|
||||
* interface which aren't explicitly implemented by AbstractMessage are forwarded to the wrapped
|
||||
* object. This allows us to test that AbstractMessage's implementations work even if the wrapped
|
||||
* object does not use them.
|
||||
*/
|
||||
private static class AbstractMessageWrapper extends AbstractMessage {
|
||||
@ -70,39 +69,47 @@ public class AbstractMessageTest extends TestCase {
|
||||
public Descriptors.Descriptor getDescriptorForType() {
|
||||
return wrappedMessage.getDescriptorForType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMessageWrapper getDefaultInstanceForType() {
|
||||
return new AbstractMessageWrapper(
|
||||
wrappedMessage.getDefaultInstanceForType());
|
||||
return new AbstractMessageWrapper(wrappedMessage.getDefaultInstanceForType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
|
||||
return wrappedMessage.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(Descriptors.FieldDescriptor field) {
|
||||
return wrappedMessage.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(Descriptors.FieldDescriptor field) {
|
||||
return wrappedMessage.getField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
|
||||
return wrappedMessage.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
|
||||
return wrappedMessage.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return wrappedMessage.getUnknownFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForType() {
|
||||
return new Builder(wrappedMessage.newBuilderForType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder(wrappedMessage.toBuilder());
|
||||
@ -119,85 +126,103 @@ public class AbstractMessageTest extends TestCase {
|
||||
public AbstractMessageWrapper build() {
|
||||
return new AbstractMessageWrapper(wrappedBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMessageWrapper buildPartial() {
|
||||
return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clone() {
|
||||
return new Builder(wrappedBuilder.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return clone().buildPartial().isInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Descriptors.Descriptor getDescriptorForType() {
|
||||
return wrappedBuilder.getDescriptorForType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMessageWrapper getDefaultInstanceForType() {
|
||||
return new AbstractMessageWrapper(
|
||||
wrappedBuilder.getDefaultInstanceForType());
|
||||
return new AbstractMessageWrapper(wrappedBuilder.getDefaultInstanceForType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
|
||||
return wrappedBuilder.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
|
||||
return new Builder(wrappedBuilder.newBuilderForField(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(Descriptors.FieldDescriptor field) {
|
||||
return wrappedBuilder.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(Descriptors.FieldDescriptor field) {
|
||||
return wrappedBuilder.getField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setField(Descriptors.FieldDescriptor field, Object value) {
|
||||
wrappedBuilder.setField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clearField(Descriptors.FieldDescriptor field) {
|
||||
wrappedBuilder.clearField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
|
||||
return wrappedBuilder.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
|
||||
return wrappedBuilder.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) {
|
||||
wrappedBuilder.setRepeatedField(field, index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
|
||||
wrappedBuilder.addRepeatedField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return wrappedBuilder.getUnknownFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
|
||||
wrappedBuilder.setUnknownFields(unknownFields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message.Builder getFieldBuilder(FieldDescriptor field) {
|
||||
return wrappedBuilder.getFieldBuilder(field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser<? extends Message> getParserForType() {
|
||||
return wrappedMessage.getParserForType();
|
||||
@ -207,7 +232,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
// =================================================================
|
||||
|
||||
TestUtil.ReflectionTester reflectionTester =
|
||||
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
|
||||
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
|
||||
|
||||
TestUtil.ReflectionTester extensionsReflectionTester =
|
||||
new TestUtil.ReflectionTester(
|
||||
@ -215,16 +240,17 @@ public class AbstractMessageTest extends TestCase {
|
||||
|
||||
public void testClear() throws Exception {
|
||||
AbstractMessageWrapper message =
|
||||
new AbstractMessageWrapper.Builder(
|
||||
TestAllTypes.newBuilder(TestUtil.getAllSet()))
|
||||
.clear().build();
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(TestUtil.getAllSet()))
|
||||
.clear()
|
||||
.build();
|
||||
TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
public void testCopy() throws Exception {
|
||||
AbstractMessageWrapper message =
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
|
||||
.mergeFrom(TestUtil.getAllSet()).build();
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
|
||||
.mergeFrom(TestUtil.getAllSet())
|
||||
.build();
|
||||
TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
@ -232,25 +258,21 @@ public class AbstractMessageTest extends TestCase {
|
||||
TestAllTypes message = TestUtil.getAllSet();
|
||||
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
|
||||
|
||||
assertEquals(message.getSerializedSize(),
|
||||
abstractMessage.getSerializedSize());
|
||||
assertEquals(message.getSerializedSize(), abstractMessage.getSerializedSize());
|
||||
}
|
||||
|
||||
public void testSerialization() throws Exception {
|
||||
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
|
||||
|
||||
TestUtil.assertAllFieldsSet(
|
||||
TestAllTypes.parseFrom(abstractMessage.toByteString()));
|
||||
TestUtil.assertAllFieldsSet(TestAllTypes.parseFrom(abstractMessage.toByteString()));
|
||||
|
||||
assertEquals(TestUtil.getAllSet().toByteString(),
|
||||
abstractMessage.toByteString());
|
||||
assertEquals(TestUtil.getAllSet().toByteString(), abstractMessage.toByteString());
|
||||
}
|
||||
|
||||
public void testParsing() throws Exception {
|
||||
AbstractMessageWrapper.Builder builder =
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
|
||||
AbstractMessageWrapper message =
|
||||
builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
|
||||
AbstractMessageWrapper message = builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
|
||||
TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
@ -270,8 +292,8 @@ public class AbstractMessageTest extends TestCase {
|
||||
}
|
||||
|
||||
// test DynamicMessage directly.
|
||||
Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
|
||||
TestRequiredForeign.getDescriptor());
|
||||
Message.Builder dynamicMessageBuilder =
|
||||
DynamicMessage.newBuilder(TestRequiredForeign.getDescriptor());
|
||||
// mergeFrom() should not throw initialization error.
|
||||
dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
|
||||
try {
|
||||
@ -283,65 +305,56 @@ public class AbstractMessageTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testPackedSerialization() throws Exception {
|
||||
Message abstractMessage =
|
||||
new AbstractMessageWrapper(TestUtil.getPackedSet());
|
||||
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getPackedSet());
|
||||
|
||||
TestUtil.assertPackedFieldsSet(
|
||||
TestPackedTypes.parseFrom(abstractMessage.toByteString()));
|
||||
TestUtil.assertPackedFieldsSet(TestPackedTypes.parseFrom(abstractMessage.toByteString()));
|
||||
|
||||
assertEquals(TestUtil.getPackedSet().toByteString(),
|
||||
abstractMessage.toByteString());
|
||||
assertEquals(TestUtil.getPackedSet().toByteString(), abstractMessage.toByteString());
|
||||
}
|
||||
|
||||
public void testPackedParsing() throws Exception {
|
||||
AbstractMessageWrapper.Builder builder =
|
||||
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
|
||||
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
|
||||
AbstractMessageWrapper message =
|
||||
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
|
||||
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
|
||||
TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
public void testUnpackedSerialization() throws Exception {
|
||||
Message abstractMessage =
|
||||
new AbstractMessageWrapper(TestUtil.getUnpackedSet());
|
||||
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getUnpackedSet());
|
||||
|
||||
TestUtil.assertUnpackedFieldsSet(
|
||||
TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
|
||||
TestUtil.assertUnpackedFieldsSet(TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
|
||||
|
||||
assertEquals(TestUtil.getUnpackedSet().toByteString(),
|
||||
abstractMessage.toByteString());
|
||||
assertEquals(TestUtil.getUnpackedSet().toByteString(), abstractMessage.toByteString());
|
||||
}
|
||||
|
||||
public void testParsePackedToUnpacked() throws Exception {
|
||||
AbstractMessageWrapper.Builder builder =
|
||||
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
|
||||
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
|
||||
AbstractMessageWrapper message =
|
||||
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
|
||||
TestUtil.assertUnpackedFieldsSet(
|
||||
(TestUnpackedTypes) message.wrappedMessage);
|
||||
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
|
||||
TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
public void testParseUnpackedToPacked() throws Exception {
|
||||
AbstractMessageWrapper.Builder builder =
|
||||
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
|
||||
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
|
||||
AbstractMessageWrapper message =
|
||||
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
|
||||
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
|
||||
TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
public void testUnpackedParsing() throws Exception {
|
||||
AbstractMessageWrapper.Builder builder =
|
||||
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
|
||||
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
|
||||
AbstractMessageWrapper message =
|
||||
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
|
||||
TestUtil.assertUnpackedFieldsSet(
|
||||
(TestUnpackedTypes) message.wrappedMessage);
|
||||
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
|
||||
TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage);
|
||||
}
|
||||
|
||||
public void testOptimizedForSize() throws Exception {
|
||||
// We're mostly only checking that this class was compiled successfully.
|
||||
TestOptimizedForSize message =
|
||||
TestOptimizedForSize.newBuilder().setI(1).build();
|
||||
TestOptimizedForSize message = TestOptimizedForSize.newBuilder().setI(1).build();
|
||||
message = TestOptimizedForSize.parseFrom(message.toByteString());
|
||||
assertEquals(2, message.getSerializedSize());
|
||||
}
|
||||
@ -351,8 +364,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
|
||||
public void testIsInitialized() throws Exception {
|
||||
TestRequired.Builder builder = TestRequired.newBuilder();
|
||||
AbstractMessageWrapper.Builder abstractBuilder =
|
||||
new AbstractMessageWrapper.Builder(builder);
|
||||
AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
|
||||
|
||||
assertFalse(abstractBuilder.isInitialized());
|
||||
assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
|
||||
@ -369,8 +381,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
|
||||
public void testForeignIsInitialized() throws Exception {
|
||||
TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
|
||||
AbstractMessageWrapper.Builder abstractBuilder =
|
||||
new AbstractMessageWrapper.Builder(builder);
|
||||
AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
|
||||
|
||||
assertTrue(abstractBuilder.isInitialized());
|
||||
assertEquals("", abstractBuilder.getInitializationErrorString());
|
||||
@ -378,8 +389,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
|
||||
assertFalse(abstractBuilder.isInitialized());
|
||||
assertEquals(
|
||||
"optional_message.b, optional_message.c",
|
||||
abstractBuilder.getInitializationErrorString());
|
||||
"optional_message.b, optional_message.c", abstractBuilder.getInitializationErrorString());
|
||||
|
||||
builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
|
||||
assertTrue(abstractBuilder.isInitialized());
|
||||
@ -400,36 +410,37 @@ public class AbstractMessageTest extends TestCase {
|
||||
// Tests for mergeFrom
|
||||
|
||||
static final TestAllTypes MERGE_SOURCE =
|
||||
TestAllTypes.newBuilder()
|
||||
.setOptionalInt32(1)
|
||||
.setOptionalString("foo")
|
||||
.setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
|
||||
.addRepeatedString("bar")
|
||||
.build();
|
||||
TestAllTypes.newBuilder()
|
||||
.setOptionalInt32(1)
|
||||
.setOptionalString("foo")
|
||||
.setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
|
||||
.addRepeatedString("bar")
|
||||
.build();
|
||||
|
||||
static final TestAllTypes MERGE_DEST =
|
||||
TestAllTypes.newBuilder()
|
||||
.setOptionalInt64(2)
|
||||
.setOptionalString("baz")
|
||||
.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
|
||||
.addRepeatedString("qux")
|
||||
.build();
|
||||
TestAllTypes.newBuilder()
|
||||
.setOptionalInt64(2)
|
||||
.setOptionalString("baz")
|
||||
.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
|
||||
.addRepeatedString("qux")
|
||||
.build();
|
||||
|
||||
static final String MERGE_RESULT_TEXT =
|
||||
"optional_int32: 1\n" +
|
||||
"optional_int64: 2\n" +
|
||||
"optional_string: \"foo\"\n" +
|
||||
"optional_foreign_message {\n" +
|
||||
" c: 3\n" +
|
||||
"}\n" +
|
||||
"repeated_string: \"qux\"\n" +
|
||||
"repeated_string: \"bar\"\n";
|
||||
""
|
||||
+ "optional_int32: 1\n"
|
||||
+ "optional_int64: 2\n"
|
||||
+ "optional_string: \"foo\"\n"
|
||||
+ "optional_foreign_message {\n"
|
||||
+ " c: 3\n"
|
||||
+ "}\n"
|
||||
+ "repeated_string: \"qux\"\n"
|
||||
+ "repeated_string: \"bar\"\n";
|
||||
|
||||
public void testMergeFrom() throws Exception {
|
||||
AbstractMessageWrapper result =
|
||||
new AbstractMessageWrapper.Builder(
|
||||
TestAllTypes.newBuilder(MERGE_DEST))
|
||||
.mergeFrom(MERGE_SOURCE).build();
|
||||
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(MERGE_DEST))
|
||||
.mergeFrom(MERGE_SOURCE)
|
||||
.build();
|
||||
|
||||
assertEquals(MERGE_RESULT_TEXT, result.toString());
|
||||
}
|
||||
@ -443,8 +454,10 @@ public class AbstractMessageTest extends TestCase {
|
||||
TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
|
||||
TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
|
||||
TestAllExtensions e = TestUtil.getAllExtensionsSet();
|
||||
TestAllExtensions f = TestAllExtensions.newBuilder(e)
|
||||
.addExtension(UnittestProto.repeatedInt32Extension, 999).build();
|
||||
TestAllExtensions f =
|
||||
TestAllExtensions.newBuilder(e)
|
||||
.addExtension(UnittestProto.repeatedInt32Extension, 999)
|
||||
.build();
|
||||
|
||||
checkEqualsIsConsistent(a);
|
||||
checkEqualsIsConsistent(b);
|
||||
@ -489,9 +502,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given proto has symmetric equals and hashCode methods.
|
||||
*/
|
||||
/** Asserts that the given proto has symmetric equals and hashCode methods. */
|
||||
private void checkEqualsIsConsistent(Message message) {
|
||||
// Object should be equal to itself.
|
||||
assertEquals(message, message);
|
||||
@ -501,9 +512,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
checkEqualsIsConsistent(message, dynamic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given protos are equal and have the same hash code.
|
||||
*/
|
||||
/** Asserts that the given protos are equal and have the same hash code. */
|
||||
private void checkEqualsIsConsistent(Message message1, Message message2) {
|
||||
assertEquals(message1, message2);
|
||||
assertEquals(message2, message1);
|
||||
@ -513,9 +522,8 @@ public class AbstractMessageTest extends TestCase {
|
||||
/**
|
||||
* Asserts that the given protos are not equal and have different hash codes.
|
||||
*
|
||||
* @warning It's valid for non-equal objects to have the same hash code, so
|
||||
* this test is stricter than it needs to be. However, this should happen
|
||||
* relatively rarely.
|
||||
* @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
|
||||
* than it needs to be. However, this should happen relatively rarely.
|
||||
*/
|
||||
private void checkNotEqual(Message m1, Message m2) {
|
||||
String equalsError = String.format("%s should not be equal to %s", m1, m2);
|
||||
@ -535,7 +543,7 @@ public class AbstractMessageTest extends TestCase {
|
||||
|
||||
public void testCheckByteStringIsUtf8OnNonUtf8() {
|
||||
ByteString byteString =
|
||||
ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
|
||||
ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte.
|
||||
try {
|
||||
AbstractMessageLite.checkByteStringIsUtf8(byteString);
|
||||
fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
|
||||
@ -543,5 +551,4 @@ public class AbstractMessageTest extends TestCase {
|
||||
assertEquals("Byte string is not UTF-8.", exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ package com.google.protobuf;
|
||||
|
||||
import any_test.AnyTestProto.TestAny;
|
||||
import protobuf_unittest.UnittestProto.TestAllTypes;
|
||||
|
||||
import java.util.Objects;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ public class AnyTest extends TestCase {
|
||||
|
||||
// Unpacking to a wrong type will throw an exception.
|
||||
try {
|
||||
TestAny wrongMessage = container.getValue().unpack(TestAny.class);
|
||||
container.getValue().unpack(TestAny.class);
|
||||
fail("Exception is expected.");
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// expected.
|
||||
@ -68,7 +68,7 @@ public class AnyTest extends TestCase {
|
||||
ByteString.copyFrom(new byte[]{0x11}));
|
||||
container = containerBuilder.build();
|
||||
try {
|
||||
TestAllTypes parsingFailed = container.getValue().unpack(TestAllTypes.class);
|
||||
container.getValue().unpack(TestAllTypes.class);
|
||||
fail("Exception is expected.");
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// expected.
|
||||
@ -132,6 +132,6 @@ public class AnyTest extends TestCase {
|
||||
|
||||
TestAllTypes result1 = container.getValue().unpack(TestAllTypes.class);
|
||||
TestAllTypes result2 = container.getValue().unpack(TestAllTypes.class);
|
||||
assertTrue(result1 == result2);
|
||||
assertTrue(Objects.equals(result1, result2));
|
||||
}
|
||||
}
|
||||
|
@ -45,8 +45,7 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class BooleanArrayListTest extends TestCase {
|
||||
|
||||
private static final BooleanArrayList UNARY_LIST =
|
||||
newImmutableBooleanArrayList(true);
|
||||
private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
|
||||
private static final BooleanArrayList TERTIARY_LIST =
|
||||
newImmutableBooleanArrayList(true, false, true);
|
||||
|
||||
@ -78,10 +77,10 @@ public class BooleanArrayListTest extends TestCase {
|
||||
list.addAll(asList(true, false, true, false));
|
||||
Iterator<Boolean> iterator = list.iterator();
|
||||
assertEquals(4, list.size());
|
||||
assertEquals(true, (boolean) list.get(0));
|
||||
assertEquals(true, (boolean) iterator.next());
|
||||
assertTrue(list.get(0));
|
||||
assertTrue(iterator.next());
|
||||
list.set(0, true);
|
||||
assertEquals(false, (boolean) iterator.next());
|
||||
assertFalse(iterator.next());
|
||||
|
||||
list.remove(0);
|
||||
try {
|
||||
@ -102,9 +101,9 @@ public class BooleanArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testGet() {
|
||||
assertEquals(true, (boolean) TERTIARY_LIST.get(0));
|
||||
assertEquals(false, (boolean) TERTIARY_LIST.get(1));
|
||||
assertEquals(true, (boolean) TERTIARY_LIST.get(2));
|
||||
assertTrue(TERTIARY_LIST.get(0));
|
||||
assertFalse(TERTIARY_LIST.get(1));
|
||||
assertTrue(TERTIARY_LIST.get(2));
|
||||
|
||||
try {
|
||||
TERTIARY_LIST.get(-1);
|
||||
@ -122,9 +121,9 @@ public class BooleanArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testGetBoolean() {
|
||||
assertEquals(true, TERTIARY_LIST.getBoolean(0));
|
||||
assertEquals(false, TERTIARY_LIST.getBoolean(1));
|
||||
assertEquals(true, TERTIARY_LIST.getBoolean(2));
|
||||
assertTrue(TERTIARY_LIST.getBoolean(0));
|
||||
assertFalse(TERTIARY_LIST.getBoolean(1));
|
||||
assertTrue(TERTIARY_LIST.getBoolean(2));
|
||||
|
||||
try {
|
||||
TERTIARY_LIST.get(-1);
|
||||
@ -163,11 +162,11 @@ public class BooleanArrayListTest extends TestCase {
|
||||
list.addBoolean(false);
|
||||
list.addBoolean(false);
|
||||
|
||||
assertEquals(false, (boolean) list.set(0, true));
|
||||
assertEquals(true, list.getBoolean(0));
|
||||
assertFalse(list.set(0, true));
|
||||
assertTrue(list.getBoolean(0));
|
||||
|
||||
assertEquals(false, (boolean) list.set(1, false));
|
||||
assertEquals(false, list.getBoolean(1));
|
||||
assertFalse(list.set(1, false));
|
||||
assertFalse(list.getBoolean(1));
|
||||
|
||||
try {
|
||||
list.set(-1, false);
|
||||
@ -188,11 +187,11 @@ public class BooleanArrayListTest extends TestCase {
|
||||
list.addBoolean(true);
|
||||
list.addBoolean(true);
|
||||
|
||||
assertEquals(true, list.setBoolean(0, false));
|
||||
assertEquals(false, list.getBoolean(0));
|
||||
assertTrue(list.setBoolean(0, false));
|
||||
assertFalse(list.getBoolean(0));
|
||||
|
||||
assertEquals(true, list.setBoolean(1, false));
|
||||
assertEquals(false, list.getBoolean(1));
|
||||
assertTrue(list.setBoolean(1, false));
|
||||
assertFalse(list.getBoolean(1));
|
||||
|
||||
try {
|
||||
list.setBoolean(-1, false);
|
||||
@ -226,8 +225,7 @@ public class BooleanArrayListTest extends TestCase {
|
||||
list.add(i % 2 == 0);
|
||||
}
|
||||
assertEquals(
|
||||
asList(false, true, false, false, true, true, false, true, false, true, false),
|
||||
list);
|
||||
asList(false, true, false, false, true, true, false, true, false, true, false), list);
|
||||
|
||||
try {
|
||||
list.add(-1, true);
|
||||
@ -257,8 +255,8 @@ public class BooleanArrayListTest extends TestCase {
|
||||
|
||||
assertTrue(list.addAll(Collections.singleton(true)));
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(true, (boolean) list.get(0));
|
||||
assertEquals(true, list.getBoolean(0));
|
||||
assertTrue(list.get(0));
|
||||
assertTrue(list.getBoolean(0));
|
||||
|
||||
assertTrue(list.addAll(asList(false, true, false, true, false)));
|
||||
assertEquals(asList(true, false, true, false, true, false), list);
|
||||
@ -272,7 +270,7 @@ public class BooleanArrayListTest extends TestCase {
|
||||
|
||||
public void testRemove() {
|
||||
list.addAll(TERTIARY_LIST);
|
||||
assertEquals(true, (boolean) list.remove(0));
|
||||
assertTrue(list.remove(0));
|
||||
assertEquals(asList(false, true), list);
|
||||
|
||||
assertTrue(list.remove(Boolean.TRUE));
|
||||
@ -281,7 +279,7 @@ public class BooleanArrayListTest extends TestCase {
|
||||
assertFalse(list.remove(Boolean.TRUE));
|
||||
assertEquals(asList(false), list);
|
||||
|
||||
assertEquals(false, (boolean) list.remove(0));
|
||||
assertFalse(list.remove(0));
|
||||
assertEquals(asList(), list);
|
||||
|
||||
try {
|
||||
@ -299,16 +297,14 @@ public class BooleanArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testRemoveEndOfCapacity() {
|
||||
BooleanList toRemove =
|
||||
BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addBoolean(true);
|
||||
toRemove.remove(0);
|
||||
assertEquals(0, toRemove.size());
|
||||
}
|
||||
|
||||
public void testSublistRemoveEndOfCapacity() {
|
||||
BooleanList toRemove =
|
||||
BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addBoolean(true);
|
||||
toRemove.subList(0, 1).clear();
|
||||
assertEquals(0, toRemove.size());
|
||||
|
@ -38,9 +38,9 @@ import java.io.ObjectOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
|
||||
* by inheriting the tests from {@link LiteralByteStringTest}. The only method which
|
||||
* is strange enough that it needs to be overridden here is {@link #testToString()}.
|
||||
* This class tests {@link BoundedByteString}, which extends {@link LiteralByteString}, by
|
||||
* inheriting the tests from {@link LiteralByteStringTest}. The only method which is strange enough
|
||||
* that it needs to be overridden here is {@link #testToString()}.
|
||||
*
|
||||
* @author carlanton@google.com (Carl Haverl)
|
||||
*/
|
||||
@ -63,12 +63,16 @@ public class BoundedByteStringTest extends LiteralByteStringTest {
|
||||
String testString = "I love unicode \u1234\u5678 characters";
|
||||
ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
|
||||
ByteString chopped = unicode.substring(2, unicode.size() - 6);
|
||||
assertEquals(classUnderTest + ".substring() must have the expected type",
|
||||
classUnderTest, getActualClassName(chopped));
|
||||
assertEquals(
|
||||
classUnderTest + ".substring() must have the expected type",
|
||||
classUnderTest,
|
||||
getActualClassName(chopped));
|
||||
|
||||
String roundTripString = chopped.toString(UTF_8);
|
||||
assertEquals(classUnderTest + " unicode bytes must match",
|
||||
testString.substring(2, testString.length() - 6), roundTripString);
|
||||
assertEquals(
|
||||
classUnderTest + " unicode bytes must match",
|
||||
testString.substring(2, testString.length() - 6),
|
||||
roundTripString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,12 +80,16 @@ public class BoundedByteStringTest extends LiteralByteStringTest {
|
||||
String testString = "I love unicode \u1234\u5678 characters";
|
||||
ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
|
||||
ByteString chopped = unicode.substring(2, unicode.size() - 6);
|
||||
assertEquals(classUnderTest + ".substring() must have the expected type",
|
||||
classUnderTest, getActualClassName(chopped));
|
||||
assertEquals(
|
||||
classUnderTest + ".substring() must have the expected type",
|
||||
classUnderTest,
|
||||
getActualClassName(chopped));
|
||||
|
||||
String roundTripString = chopped.toString(Internal.UTF_8);
|
||||
assertEquals(classUnderTest + " unicode bytes must match",
|
||||
testString.substring(2, testString.length() - 6), roundTripString);
|
||||
assertEquals(
|
||||
classUnderTest + " unicode bytes must match",
|
||||
testString.substring(2, testString.length() - 6),
|
||||
roundTripString);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,9 +37,7 @@ import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link ByteBufferWriter}.
|
||||
*/
|
||||
/** Tests for {@link ByteBufferWriter}. */
|
||||
public class ByteBufferWriterTest extends TestCase {
|
||||
|
||||
public void testHeapBuffer() throws IOException {
|
||||
|
@ -124,22 +124,24 @@ public class ByteStringTest extends TestCase {
|
||||
public void testSubstring_BeginIndex() {
|
||||
byte[] bytes = getTestBytes();
|
||||
ByteString substring = ByteString.copyFrom(bytes).substring(500);
|
||||
assertTrue("substring must contain the tail of the string",
|
||||
assertTrue(
|
||||
"substring must contain the tail of the string",
|
||||
isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
|
||||
}
|
||||
|
||||
public void testCopyFrom_BytesOffsetSize() {
|
||||
byte[] bytes = getTestBytes();
|
||||
ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
|
||||
assertTrue("copyFrom sub-range must contain the expected bytes",
|
||||
assertTrue(
|
||||
"copyFrom sub-range must contain the expected bytes",
|
||||
isArrayRange(byteString.toByteArray(), bytes, 500, 200));
|
||||
}
|
||||
|
||||
public void testCopyFrom_Bytes() {
|
||||
byte[] bytes = getTestBytes();
|
||||
ByteString byteString = ByteString.copyFrom(bytes);
|
||||
assertTrue("copyFrom must contain the expected bytes",
|
||||
isArray(byteString.toByteArray(), bytes));
|
||||
assertTrue(
|
||||
"copyFrom must contain the expected bytes", isArray(byteString.toByteArray(), bytes));
|
||||
}
|
||||
|
||||
public void testCopyFrom_ByteBufferSize() {
|
||||
@ -148,7 +150,8 @@ public class ByteStringTest extends TestCase {
|
||||
byteBuffer.put(bytes);
|
||||
byteBuffer.position(500);
|
||||
ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
|
||||
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
assertTrue(
|
||||
"copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
isArrayRange(byteString.toByteArray(), bytes, 500, 200));
|
||||
}
|
||||
|
||||
@ -158,7 +161,8 @@ public class ByteStringTest extends TestCase {
|
||||
byteBuffer.put(bytes);
|
||||
byteBuffer.position(500);
|
||||
ByteString byteString = ByteString.copyFrom(byteBuffer);
|
||||
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
assertTrue(
|
||||
"copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
|
||||
}
|
||||
|
||||
@ -166,7 +170,8 @@ public class ByteStringTest extends TestCase {
|
||||
String testString = "I love unicode \u1234\u5678 characters";
|
||||
ByteString byteString = ByteString.copyFrom(testString, UTF_16);
|
||||
byte[] testBytes = testString.getBytes(UTF_16);
|
||||
assertTrue("copyFrom string must respect the charset",
|
||||
assertTrue(
|
||||
"copyFrom string must respect the charset",
|
||||
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
||||
}
|
||||
|
||||
@ -174,7 +179,8 @@ public class ByteStringTest extends TestCase {
|
||||
String testString = "I love unicode \u1234\u5678 characters";
|
||||
ByteString byteString = ByteString.copyFromUtf8(testString);
|
||||
byte[] testBytes = testString.getBytes(Internal.UTF_8);
|
||||
assertTrue("copyFromUtf8 string must respect the charset",
|
||||
assertTrue(
|
||||
"copyFromUtf8 string must respect the charset",
|
||||
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
||||
}
|
||||
|
||||
@ -183,17 +189,20 @@ public class ByteStringTest extends TestCase {
|
||||
final List<ByteString> pieces = makeConcretePieces(testBytes);
|
||||
// Call copyFrom() on a Collection
|
||||
ByteString byteString = ByteString.copyFrom(pieces);
|
||||
assertTrue("copyFrom a List must contain the expected bytes",
|
||||
assertTrue(
|
||||
"copyFrom a List must contain the expected bytes",
|
||||
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
|
||||
// Call copyFrom on an iteration that's not a collection
|
||||
ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
|
||||
@Override
|
||||
public Iterator<ByteString> iterator() {
|
||||
return pieces.iterator();
|
||||
}
|
||||
});
|
||||
assertEquals("copyFrom from an Iteration must contain the expected bytes",
|
||||
byteString, byteStringAlt);
|
||||
ByteString byteStringAlt =
|
||||
ByteString.copyFrom(
|
||||
new Iterable<ByteString>() {
|
||||
@Override
|
||||
public Iterator<ByteString> iterator() {
|
||||
return pieces.iterator();
|
||||
}
|
||||
});
|
||||
assertEquals(
|
||||
"copyFrom from an Iteration must contain the expected bytes", byteString, byteStringAlt);
|
||||
}
|
||||
|
||||
public void testCopyFrom_LengthTooBig() {
|
||||
@ -229,15 +238,17 @@ public class ByteStringTest extends TestCase {
|
||||
ByteString byteString = ByteString.copyFrom(bytes);
|
||||
byte[] target = new byte[bytes.length + 1000];
|
||||
byteString.copyTo(target, 400);
|
||||
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
assertTrue(
|
||||
"copyFrom byteBuffer sub-range must contain the expected bytes",
|
||||
isArrayRange(bytes, target, 400, bytes.length));
|
||||
}
|
||||
|
||||
public void testReadFrom_emptyStream() throws IOException {
|
||||
ByteString byteString =
|
||||
ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
|
||||
assertSame("reading an empty stream must result in the EMPTY constant "
|
||||
+ "byte string", ByteString.EMPTY, byteString);
|
||||
ByteString byteString = ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
|
||||
assertSame(
|
||||
"reading an empty stream must result in the EMPTY constant byte string",
|
||||
ByteString.EMPTY,
|
||||
byteString);
|
||||
}
|
||||
|
||||
public void testReadFrom_smallStream() throws IOException {
|
||||
@ -245,18 +256,18 @@ public class ByteStringTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testReadFrom_mutating() throws IOException {
|
||||
byte[] capturedArray = null;
|
||||
EvilInputStream eis = new EvilInputStream();
|
||||
ByteString byteString = ByteString.readFrom(eis);
|
||||
byte[] capturedArray = eis.capturedArray;
|
||||
|
||||
capturedArray = eis.capturedArray;
|
||||
byte[] originalValue = byteString.toByteArray();
|
||||
for (int x = 0; x < capturedArray.length; ++x) {
|
||||
capturedArray[x] = (byte) 0;
|
||||
}
|
||||
|
||||
byte[] newValue = byteString.toByteArray();
|
||||
assertTrue("copyFrom byteBuffer must not grant access to underlying array",
|
||||
assertTrue(
|
||||
"copyFrom byteBuffer must not grant access to underlying array",
|
||||
Arrays.equals(originalValue, newValue));
|
||||
}
|
||||
|
||||
@ -318,8 +329,8 @@ public class ByteStringTest extends TestCase {
|
||||
fail("readFrom must throw the underlying IOException");
|
||||
|
||||
} catch (IOException e) {
|
||||
assertEquals("readFrom must throw the expected exception",
|
||||
"synthetic failure", e.getMessage());
|
||||
assertEquals(
|
||||
"readFrom must throw the expected exception", "synthetic failure", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +340,8 @@ public class ByteStringTest extends TestCase {
|
||||
final byte[] data = getTestBytes(0x1000);
|
||||
|
||||
ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
|
||||
assertTrue("readFrom byte stream must contain the expected bytes",
|
||||
assertTrue(
|
||||
"readFrom byte stream must contain the expected bytes",
|
||||
isArray(byteString.toByteArray(), data));
|
||||
|
||||
// Same test as above, but with some specific chunk sizes.
|
||||
@ -344,11 +356,10 @@ public class ByteStringTest extends TestCase {
|
||||
|
||||
// Fails unless ByteString.readFrom reads the bytes correctly from a
|
||||
// reluctant stream with the given chunkSize parameter.
|
||||
private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
|
||||
throws IOException {
|
||||
private void assertReadFromReluctantStream(byte[] bytes, int chunkSize) throws IOException {
|
||||
ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
|
||||
assertTrue("readFrom byte stream must contain the expected bytes",
|
||||
isArray(b.toByteArray(), bytes));
|
||||
assertTrue(
|
||||
"readFrom byte stream must contain the expected bytes", isArray(b.toByteArray(), bytes));
|
||||
}
|
||||
|
||||
// Tests that ByteString.readFrom works with streams that implement
|
||||
@ -357,21 +368,23 @@ public class ByteStringTest extends TestCase {
|
||||
final byte[] data = getTestBytes(0x1001);
|
||||
|
||||
ByteString byteString = ByteString.readFrom(new AvailableStream(data));
|
||||
assertTrue("readFrom byte stream must contain the expected bytes",
|
||||
assertTrue(
|
||||
"readFrom byte stream must contain the expected bytes",
|
||||
isArray(byteString.toByteArray(), data));
|
||||
}
|
||||
|
||||
// Fails unless ByteString.readFrom reads the bytes correctly.
|
||||
private void assertReadFrom(byte[] bytes) throws IOException {
|
||||
ByteString byteString =
|
||||
ByteString.readFrom(new ByteArrayInputStream(bytes));
|
||||
assertTrue("readFrom byte stream must contain the expected bytes",
|
||||
ByteString byteString = ByteString.readFrom(new ByteArrayInputStream(bytes));
|
||||
assertTrue(
|
||||
"readFrom byte stream must contain the expected bytes",
|
||||
isArray(byteString.toByteArray(), bytes));
|
||||
}
|
||||
|
||||
// A stream that fails when read.
|
||||
private static final class FailStream extends InputStream {
|
||||
@Override public int read() throws IOException {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
throw new IOException("synthetic failure");
|
||||
}
|
||||
}
|
||||
@ -386,7 +399,8 @@ public class ByteStringTest extends TestCase {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override public int read() {
|
||||
@Override
|
||||
public int read() {
|
||||
if (pos == data.length) {
|
||||
return -1;
|
||||
} else {
|
||||
@ -394,11 +408,13 @@ public class ByteStringTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int read(byte[] buf) {
|
||||
@Override
|
||||
public int read(byte[] buf) {
|
||||
return read(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
@Override public int read(byte[] buf, int offset, int size) {
|
||||
@Override
|
||||
public int read(byte[] buf, int offset, int size) {
|
||||
if (pos == data.length) {
|
||||
return -1;
|
||||
}
|
||||
@ -415,7 +431,8 @@ public class ByteStringTest extends TestCase {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override public int available() {
|
||||
@Override
|
||||
public int available() {
|
||||
return Math.min(250, data.length - pos);
|
||||
}
|
||||
}
|
||||
@ -465,8 +482,8 @@ public class ByteStringTest extends TestCase {
|
||||
String testString = "I love unicode \u1234\u5678 characters";
|
||||
byte[] testBytes = testString.getBytes(Internal.UTF_8);
|
||||
ByteString byteString = ByteString.copyFrom(testBytes);
|
||||
assertEquals("copyToStringUtf8 must respect the charset",
|
||||
testString, byteString.toStringUtf8());
|
||||
assertEquals(
|
||||
"copyToStringUtf8 must respect the charset", testString, byteString.toStringUtf8());
|
||||
}
|
||||
|
||||
public void testNewOutput_InitialCapacity() throws IOException {
|
||||
@ -484,8 +501,9 @@ public class ByteStringTest extends TestCase {
|
||||
public void testNewOutput_ArrayWrite() {
|
||||
byte[] bytes = getTestBytes();
|
||||
int length = bytes.length;
|
||||
int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
|
||||
2 * length, 3 * length};
|
||||
int[] bufferSizes = {
|
||||
128, 256, length / 2, length - 1, length, length + 1, 2 * length, 3 * length
|
||||
};
|
||||
int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
|
||||
|
||||
for (int bufferSize : bufferSizes) {
|
||||
@ -496,7 +514,8 @@ public class ByteStringTest extends TestCase {
|
||||
output.write(bytes, i, Math.min(writeSize, length - i));
|
||||
}
|
||||
ByteString byteString = output.toByteString();
|
||||
assertTrue("String built from newOutput() must contain the expected bytes",
|
||||
assertTrue(
|
||||
"String built from newOutput() must contain the expected bytes",
|
||||
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
||||
}
|
||||
}
|
||||
@ -507,16 +526,17 @@ public class ByteStringTest extends TestCase {
|
||||
public void testNewOutput_WriteChar() {
|
||||
byte[] bytes = getTestBytes();
|
||||
int length = bytes.length;
|
||||
int[] bufferSizes = {0, 1, 128, 256, length / 2,
|
||||
length - 1, length, length + 1,
|
||||
2 * length, 3 * length};
|
||||
int[] bufferSizes = {
|
||||
0, 1, 128, 256, length / 2, length - 1, length, length + 1, 2 * length, 3 * length
|
||||
};
|
||||
for (int bufferSize : bufferSizes) {
|
||||
ByteString.Output output = ByteString.newOutput(bufferSize);
|
||||
for (byte byteValue : bytes) {
|
||||
output.write(byteValue);
|
||||
}
|
||||
ByteString byteString = output.toByteString();
|
||||
assertTrue("String built from newOutput() must contain the expected bytes",
|
||||
assertTrue(
|
||||
"String built from newOutput() must contain the expected bytes",
|
||||
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
||||
}
|
||||
}
|
||||
@ -527,9 +547,9 @@ public class ByteStringTest extends TestCase {
|
||||
Random rng = new Random(1);
|
||||
byte[] bytes = getTestBytes();
|
||||
int length = bytes.length;
|
||||
int[] bufferSizes = {0, 1, 128, 256, length / 2,
|
||||
length - 1, length, length + 1,
|
||||
2 * length, 3 * length};
|
||||
int[] bufferSizes = {
|
||||
0, 1, 128, 256, length / 2, length - 1, length, length + 1, 2 * length, 3 * length
|
||||
};
|
||||
|
||||
for (int bufferSize : bufferSizes) {
|
||||
// Test writing the entire output using a mixture of write sizes and
|
||||
@ -546,12 +566,13 @@ public class ByteStringTest extends TestCase {
|
||||
position++;
|
||||
}
|
||||
assertEquals("size() returns the right value", position, output.size());
|
||||
assertTrue("newOutput() substring must have correct bytes",
|
||||
isArrayRange(output.toByteString().toByteArray(),
|
||||
bytes, 0, position));
|
||||
assertTrue(
|
||||
"newOutput() substring must have correct bytes",
|
||||
isArrayRange(output.toByteString().toByteArray(), bytes, 0, position));
|
||||
}
|
||||
ByteString byteString = output.toByteString();
|
||||
assertTrue("String built from newOutput() must contain the expected bytes",
|
||||
assertTrue(
|
||||
"String built from newOutput() must contain the expected bytes",
|
||||
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
||||
}
|
||||
}
|
||||
@ -572,7 +593,8 @@ public class ByteStringTest extends TestCase {
|
||||
byte[] oldValue = byteString.toByteArray();
|
||||
Arrays.fill(capturedArray, (byte) 0);
|
||||
byte[] newValue = byteString.toByteArray();
|
||||
assertTrue("Output must not provide access to the underlying byte array",
|
||||
assertTrue(
|
||||
"Output must not provide access to the underlying byte array",
|
||||
Arrays.equals(oldValue, newValue));
|
||||
}
|
||||
|
||||
@ -581,14 +603,15 @@ public class ByteStringTest extends TestCase {
|
||||
ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
|
||||
builder.getCodedOutput().writeRawBytes(bytes);
|
||||
ByteString byteString = builder.build();
|
||||
assertTrue("String built from newCodedBuilder() must contain the expected bytes",
|
||||
assertTrue(
|
||||
"String built from newCodedBuilder() must contain the expected bytes",
|
||||
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
|
||||
}
|
||||
|
||||
public void testSubstringParity() {
|
||||
byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
|
||||
int start = 512 * 1024 - 3333;
|
||||
int end = 512 * 1024 + 7777;
|
||||
int end = 512 * 1024 + 7777;
|
||||
ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
|
||||
boolean ok = true;
|
||||
for (int i = start; ok && i < end; ++i) {
|
||||
@ -597,10 +620,11 @@ public class ByteStringTest extends TestCase {
|
||||
assertTrue("Concrete substring didn't capture the right bytes", ok);
|
||||
|
||||
ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
|
||||
assertTrue("Substring must be equal to literal string",
|
||||
concreteSubstring.equals(literalString));
|
||||
assertEquals("Substring must have same hashcode as literal string",
|
||||
literalString.hashCode(), concreteSubstring.hashCode());
|
||||
assertEquals("Substring must be equal to literal string", literalString, concreteSubstring);
|
||||
assertEquals(
|
||||
"Substring must have same hashcode as literal string",
|
||||
literalString.hashCode(),
|
||||
concreteSubstring.hashCode());
|
||||
}
|
||||
|
||||
public void testCompositeSubstring() {
|
||||
@ -626,15 +650,22 @@ public class ByteStringTest extends TestCase {
|
||||
assertTrue("Substring must support byteAt() correctly", stillEqual);
|
||||
|
||||
ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
|
||||
assertTrue("Composite substring must equal a literal substring over the same bytes",
|
||||
compositeSubstring.equals(literalSubstring));
|
||||
assertTrue("Literal substring must equal a composite substring over the same bytes",
|
||||
literalSubstring.equals(compositeSubstring));
|
||||
assertEquals(
|
||||
"Composite substring must equal a literal substring over the same bytes",
|
||||
literalSubstring,
|
||||
compositeSubstring);
|
||||
assertEquals(
|
||||
"Literal substring must equal a composite substring over the same bytes",
|
||||
compositeSubstring,
|
||||
literalSubstring);
|
||||
|
||||
assertEquals("We must get the same hashcodes for composite and literal substrings",
|
||||
literalSubstring.hashCode(), compositeSubstring.hashCode());
|
||||
assertEquals(
|
||||
"We must get the same hashcodes for composite and literal substrings",
|
||||
literalSubstring.hashCode(),
|
||||
compositeSubstring.hashCode());
|
||||
|
||||
assertFalse("We can't be equal to a proper substring",
|
||||
assertFalse(
|
||||
"We can't be equal to a proper substring",
|
||||
compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
|
||||
}
|
||||
|
||||
@ -645,10 +676,11 @@ public class ByteStringTest extends TestCase {
|
||||
List<ByteString> pieces = makeConcretePieces(referenceBytes);
|
||||
ByteString listString = ByteString.copyFrom(pieces);
|
||||
|
||||
assertTrue("Composite string must be equal to literal string",
|
||||
listString.equals(literalString));
|
||||
assertEquals("Composite string must have same hashcode as literal string",
|
||||
literalString.hashCode(), listString.hashCode());
|
||||
assertEquals("Composite string must be equal to literal string", literalString, listString);
|
||||
assertEquals(
|
||||
"Composite string must have same hashcode as literal string",
|
||||
literalString.hashCode(),
|
||||
listString.hashCode());
|
||||
}
|
||||
|
||||
public void testConcat() {
|
||||
@ -663,30 +695,34 @@ public class ByteStringTest extends TestCase {
|
||||
concatenatedString = concatenatedString.concat(iter.next());
|
||||
}
|
||||
|
||||
assertTrue("Concatenated string must be equal to literal string",
|
||||
concatenatedString.equals(literalString));
|
||||
assertEquals("Concatenated string must have same hashcode as literal string",
|
||||
literalString.hashCode(), concatenatedString.hashCode());
|
||||
assertEquals(
|
||||
"Concatenated string must be equal to literal string", literalString, concatenatedString);
|
||||
assertEquals(
|
||||
"Concatenated string must have same hashcode as literal string",
|
||||
literalString.hashCode(),
|
||||
concatenatedString.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the Rope implementation can deal with Empty nodes, even though we
|
||||
* guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
|
||||
* Test the Rope implementation can deal with Empty nodes, even though we guard against them. See
|
||||
* also {@link LiteralByteStringTest#testConcat_empty()}.
|
||||
*/
|
||||
public void testConcat_empty() {
|
||||
byte[] referenceBytes = getTestBytes(7748, 113344L);
|
||||
ByteString literalString = ByteString.copyFrom(referenceBytes);
|
||||
|
||||
ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
|
||||
ByteString temp = RopeByteString.newInstanceForTest(
|
||||
RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
|
||||
ByteString temp =
|
||||
RopeByteString.newInstanceForTest(
|
||||
RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
|
||||
ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
|
||||
|
||||
assertTrue("String with concatenated nulls must equal simple concatenate",
|
||||
duo.equals(quintet));
|
||||
assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
|
||||
duo.hashCode(), quintet.hashCode());
|
||||
assertEquals("String with concatenated nulls must equal simple concatenate", quintet, duo);
|
||||
assertEquals(
|
||||
"String with concatenated nulls have same hashcode as simple concatenate",
|
||||
duo.hashCode(),
|
||||
quintet.hashCode());
|
||||
|
||||
ByteString.ByteIterator duoIter = duo.iterator();
|
||||
ByteString.ByteIterator quintetIter = quintet.iterator();
|
||||
@ -716,11 +752,13 @@ public class ByteStringTest extends TestCase {
|
||||
// It is possible, using the testing factory method to create deeply nested
|
||||
// trees of empty leaves, to make a string that will fail this test.
|
||||
for (int i = 1; i < duo.size(); ++i) {
|
||||
assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
|
||||
assertTrue(
|
||||
"Substrings of size() < 2 must not be RopeByteStrings",
|
||||
duo.substring(i - 1, i) instanceof ByteString.LeafByteString);
|
||||
}
|
||||
for (int i = 1; i < quintet.size(); ++i) {
|
||||
assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
|
||||
assertTrue(
|
||||
"Substrings of size() < 2 must not be RopeByteStrings",
|
||||
quintet.substring(i - 1, i) instanceof ByteString.LeafByteString);
|
||||
}
|
||||
}
|
||||
@ -769,8 +807,7 @@ public class ByteStringTest extends TestCase {
|
||||
return pieces;
|
||||
}
|
||||
|
||||
private byte[] substringUsingWriteTo(
|
||||
ByteString data, int offset, int length) throws IOException {
|
||||
private byte[] substringUsingWriteTo(ByteString data, int offset, int length) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
data.writeTo(output, offset, length);
|
||||
return output.toByteArray();
|
||||
@ -781,9 +818,7 @@ public class ByteStringTest extends TestCase {
|
||||
// won't be merged into one byte array due to some optimizations.
|
||||
final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1;
|
||||
byte[] data1 = new byte[dataSize];
|
||||
for (int i = 0; i < data1.length; i++) {
|
||||
data1[i] = (byte) 1;
|
||||
}
|
||||
Arrays.fill(data1, (byte) 1);
|
||||
data1[1] = (byte) 11;
|
||||
// Test LiteralByteString.writeTo(OutputStream,int,int)
|
||||
ByteString left = ByteString.wrap(data1);
|
||||
@ -792,9 +827,7 @@ public class ByteStringTest extends TestCase {
|
||||
assertEquals((byte) 11, result[0]);
|
||||
|
||||
byte[] data2 = new byte[dataSize];
|
||||
for (int i = 0; i < data1.length; i++) {
|
||||
data2[i] = (byte) 2;
|
||||
}
|
||||
Arrays.fill(data2, 0, data1.length, (byte) 2);
|
||||
ByteString right = ByteString.wrap(data2);
|
||||
// Concatenate two ByteStrings to create a RopeByteString.
|
||||
ByteString root = left.concat(right);
|
||||
@ -819,10 +852,8 @@ public class ByteStringTest extends TestCase {
|
||||
assertEquals((byte) 2, result[dataSize - dataSize / 2]);
|
||||
assertEquals((byte) 2, result[dataSize - 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
|
||||
*/
|
||||
|
||||
/** Tests ByteString uses Arrays based byte copier when running under Hotstop VM. */
|
||||
public void testByteArrayCopier() throws Exception {
|
||||
if (Android.isOnAndroidDevice()) {
|
||||
return;
|
||||
|
@ -38,22 +38,21 @@ import java.io.ByteArrayInputStream;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test that protos generated with file option java_string_check_utf8 do in
|
||||
* fact perform appropriate UTF-8 checks.
|
||||
* Test that protos generated with file option java_string_check_utf8 do in fact perform appropriate
|
||||
* UTF-8 checks.
|
||||
*
|
||||
* @author jbaum@google.com (Jacob Butcher)
|
||||
*/
|
||||
public class CheckUtf8Test extends TestCase {
|
||||
|
||||
private static final String UTF8_BYTE_STRING_TEXT = "some text";
|
||||
private static final ByteString UTF8_BYTE_STRING =
|
||||
ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
|
||||
private static final ByteString UTF8_BYTE_STRING = ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
|
||||
private static final ByteString NON_UTF8_BYTE_STRING =
|
||||
ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
|
||||
ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte.
|
||||
|
||||
public void testBuildRequiredStringWithGoodUtf8() throws Exception {
|
||||
assertEquals(UTF8_BYTE_STRING_TEXT,
|
||||
StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
|
||||
assertEquals(
|
||||
UTF8_BYTE_STRING_TEXT, StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
|
||||
}
|
||||
|
||||
public void testParseRequiredStringWithGoodUtf8() throws Exception {
|
||||
|
@ -699,7 +699,7 @@ public class CodedInputStreamTest extends TestCase {
|
||||
}
|
||||
assertEquals(true, input.isAtEnd());
|
||||
} catch (Exception e) {
|
||||
fail("Catch exception in the testIsAtEnd");
|
||||
throw new AssertionError("Catch exception in the testIsAtEnd", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,13 +257,27 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
// 41256202580718336
|
||||
assertWriteVarint(
|
||||
bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
|
||||
(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35)
|
||||
| (0x24L << 42) | (0x49L << 49));
|
||||
(0x00 << 0)
|
||||
| (0x66 << 7)
|
||||
| (0x6b << 14)
|
||||
| (0x1c << 21)
|
||||
| (0x43L << 28)
|
||||
| (0x49L << 35)
|
||||
| (0x24L << 42)
|
||||
| (0x49L << 49));
|
||||
// 11964378330978735131
|
||||
assertWriteVarint(
|
||||
bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
|
||||
(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35)
|
||||
| (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
|
||||
(0x1b << 0)
|
||||
| (0x28 << 7)
|
||||
| (0x79 << 14)
|
||||
| (0x42 << 21)
|
||||
| (0x3bL << 28)
|
||||
| (0x56L << 35)
|
||||
| (0x00L << 42)
|
||||
| (0x05L << 49)
|
||||
| (0x26L << 56)
|
||||
| (0x01L << 63));
|
||||
}
|
||||
|
||||
/** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
|
||||
@ -344,8 +358,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests writing a whole message with every packed field type. Ensures the
|
||||
* wire format of packed fields is compatible with C++.
|
||||
* Tests writing a whole message with every packed field type. Ensures the wire format of packed
|
||||
* fields is compatible with C++.
|
||||
*/
|
||||
public void testWriteWholePackedFieldsMessage() throws Exception {
|
||||
byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
|
||||
@ -361,8 +375,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writing a message containing a negative enum value. This used to
|
||||
* fail because the size was not properly computed as a sign-extended varint.
|
||||
* Test writing a message containing a negative enum value. This used to fail because the size was
|
||||
* not properly computed as a sign-extended varint.
|
||||
*/
|
||||
public void testWriteMessageWithNegativeEnumValue() throws Exception {
|
||||
SparseEnumMessage message =
|
||||
@ -394,8 +408,9 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
String string =
|
||||
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
|
||||
// Ensure we take the slower fast path.
|
||||
assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length())
|
||||
!= CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
|
||||
assertTrue(
|
||||
CodedOutputStream.computeUInt32SizeNoTag(string.length())
|
||||
!= CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
|
||||
|
||||
coder.stream().writeStringNoTag(string);
|
||||
coder.stream().flush();
|
||||
@ -438,9 +453,7 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
final int length2 = 8 * 1024;
|
||||
byte[] data = new byte[length2];
|
||||
for (int i = 0; i < length2; i++) {
|
||||
data[i] = (byte) 2;
|
||||
}
|
||||
Arrays.fill(data, 0, length2, (byte) 2);
|
||||
codedStream.writeRawBytes(data);
|
||||
final int length3 = bufferSize - length1 - length2;
|
||||
for (int i = 0; i < length3; i++) {
|
||||
@ -521,10 +534,14 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSerializeInvalidUtf8() throws Exception {
|
||||
String[] invalidStrings = new String[] {newString(Character.MIN_HIGH_SURROGATE),
|
||||
"foobar" + newString(Character.MIN_HIGH_SURROGATE), newString(Character.MIN_LOW_SURROGATE),
|
||||
"foobar" + newString(Character.MIN_LOW_SURROGATE),
|
||||
newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)};
|
||||
String[] invalidStrings =
|
||||
new String[] {
|
||||
newString(Character.MIN_HIGH_SURROGATE),
|
||||
"foobar" + newString(Character.MIN_HIGH_SURROGATE),
|
||||
newString(Character.MIN_LOW_SURROGATE),
|
||||
"foobar" + newString(Character.MIN_LOW_SURROGATE),
|
||||
newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)
|
||||
};
|
||||
|
||||
CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream());
|
||||
CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]);
|
||||
@ -594,16 +611,17 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
// with ASCII and Unicode characters requiring different UTF-8 byte counts per
|
||||
// char, hence causing the length delimiter varint to sometimes require more
|
||||
// bytes for the Unicode strings than the ASCII string of the same length.
|
||||
int[] lengths = new int[] {
|
||||
0,
|
||||
1,
|
||||
(1 << 4) - 1, // 1 byte for ASCII and Unicode
|
||||
(1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
|
||||
(1 << 11) - 1, // 2 bytes for ASCII and Unicode
|
||||
(1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
|
||||
(1 << 17) - 1,
|
||||
// 3 bytes for ASCII and Unicode
|
||||
};
|
||||
int[] lengths =
|
||||
new int[] {
|
||||
0,
|
||||
1,
|
||||
(1 << 4) - 1, // 1 byte for ASCII and Unicode
|
||||
(1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
|
||||
(1 << 11) - 1, // 2 bytes for ASCII and Unicode
|
||||
(1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
|
||||
(1 << 17) - 1,
|
||||
// 3 bytes for ASCII and Unicode
|
||||
};
|
||||
for (OutputType outputType : OutputType.values()) {
|
||||
for (int i : lengths) {
|
||||
testEncodingOfString(outputType, 'q', i); // 1 byte per char
|
||||
@ -626,8 +644,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given bytes using writeRawLittleEndian32() and checks
|
||||
* that the result matches the given value.
|
||||
* Parses the given bytes using writeRawLittleEndian32() and checks that the result matches the
|
||||
* given value.
|
||||
*/
|
||||
private static void assertWriteLittleEndian32(byte[] data, int value) throws Exception {
|
||||
for (OutputType outputType : OutputType.values()) {
|
||||
@ -647,8 +665,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given bytes using writeRawLittleEndian64() and checks
|
||||
* that the result matches the given value.
|
||||
* Parses the given bytes using writeRawLittleEndian64() and checks that the result matches the
|
||||
* given value.
|
||||
*/
|
||||
private static void assertWriteLittleEndian64(byte[] data, long value) throws Exception {
|
||||
for (OutputType outputType : OutputType.values()) {
|
||||
@ -691,9 +709,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to construct a byte array from a bunch of bytes. The inputs are
|
||||
* actually ints so that I can use hex notation and not get stupid errors
|
||||
* about precision.
|
||||
* Helper to construct a byte array from a bunch of bytes. The inputs are actually ints so that I
|
||||
* can use hex notation and not get stupid errors about precision.
|
||||
*/
|
||||
private static byte[] bytes(int... bytesAsInts) {
|
||||
byte[] bytes = new byte[bytesAsInts.length];
|
||||
@ -703,7 +720,7 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** Arrays.asList() does not work with arrays of primitives. :( */
|
||||
/** Arrays.asList() does not work with arrays of primitives. :( */
|
||||
private static List<Byte> toList(byte[] bytes) {
|
||||
List<Byte> result = new ArrayList<Byte>();
|
||||
for (byte b : bytes) {
|
||||
@ -717,8 +734,8 @@ public class CodedOutputStreamTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given value using writeRawVarint32() and writeRawVarint64() and
|
||||
* checks that the result matches the given bytes.
|
||||
* Writes the given value using writeRawVarint32() and writeRawVarint64() and checks that the
|
||||
* result matches the given bytes.
|
||||
*/
|
||||
private static void assertWriteVarint(byte[] data, long value) throws Exception {
|
||||
for (OutputType outputType : OutputType.values()) {
|
||||
|
@ -41,35 +41,28 @@ import junit.framework.TestCase;
|
||||
* @author birdo@google.com (Roberto Scaramuzzi)
|
||||
*/
|
||||
public class DeprecatedFieldTest extends TestCase {
|
||||
private String[] deprecatedGetterNames = {
|
||||
"hasDeprecatedInt32",
|
||||
"getDeprecatedInt32"};
|
||||
private String[] deprecatedGetterNames = {"hasDeprecatedInt32", "getDeprecatedInt32"};
|
||||
|
||||
private String[] deprecatedBuilderGetterNames = {
|
||||
"hasDeprecatedInt32",
|
||||
"getDeprecatedInt32",
|
||||
"clearDeprecatedInt32"};
|
||||
"hasDeprecatedInt32", "getDeprecatedInt32", "clearDeprecatedInt32"
|
||||
};
|
||||
|
||||
private String[] deprecatedBuilderSetterNames = {
|
||||
"setDeprecatedInt32"};
|
||||
private String[] deprecatedBuilderSetterNames = {"setDeprecatedInt32"};
|
||||
|
||||
public void testDeprecatedField() throws Exception {
|
||||
Class<?> deprecatedFields = TestDeprecatedFields.class;
|
||||
Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
|
||||
for (String name : deprecatedGetterNames) {
|
||||
Method method = deprecatedFields.getMethod(name);
|
||||
assertTrue("Method " + name + " should be deprecated",
|
||||
isDeprecated(method));
|
||||
assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
|
||||
}
|
||||
for (String name : deprecatedBuilderGetterNames) {
|
||||
Method method = deprecatedFieldsBuilder.getMethod(name);
|
||||
assertTrue("Method " + name + " should be deprecated",
|
||||
isDeprecated(method));
|
||||
assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
|
||||
}
|
||||
for (String name : deprecatedBuilderSetterNames) {
|
||||
Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
|
||||
assertTrue("Method " + name + " should be deprecated",
|
||||
isDeprecated(method));
|
||||
assertTrue("Method " + name + " should be deprecated", isDeprecated(method));
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,8 +70,7 @@ public class DeprecatedFieldTest extends TestCase {
|
||||
Class<?> oneofCase = TestDeprecatedFields.OneofFieldsCase.class;
|
||||
String name = "DEPRECATED_INT32_IN_ONEOF";
|
||||
java.lang.reflect.Field enumValue = oneofCase.getField(name);
|
||||
assertTrue("Enum value " + name + " should be deprecated.",
|
||||
isDeprecated(enumValue));
|
||||
assertTrue("Enum value " + name + " should be deprecated.", isDeprecated(enumValue));
|
||||
}
|
||||
|
||||
private boolean isDeprecated(AnnotatedElement annotated) {
|
||||
|
@ -43,15 +43,13 @@ import org.junit.runners.JUnit4;
|
||||
public class DiscardUnknownFieldsTest {
|
||||
@Test
|
||||
public void testProto2() throws Exception {
|
||||
testProto2Message(UnittestProto.TestEmptyMessage.getDefaultInstance());
|
||||
testProto2Message(UnittestProto.TestEmptyMessageWithExtensions.getDefaultInstance());
|
||||
testProto2Message(
|
||||
UnittestProto.TestEmptyMessage.getDefaultInstance());
|
||||
DynamicMessage.getDefaultInstance(UnittestProto.TestEmptyMessage.getDescriptor()));
|
||||
testProto2Message(
|
||||
UnittestProto.TestEmptyMessageWithExtensions.getDefaultInstance());
|
||||
testProto2Message(
|
||||
DynamicMessage.getDefaultInstance(UnittestProto.TestEmptyMessage.getDescriptor()));
|
||||
testProto2Message(
|
||||
DynamicMessage.getDefaultInstance(
|
||||
UnittestProto.TestEmptyMessageWithExtensions.getDescriptor()));
|
||||
DynamicMessage.getDefaultInstance(
|
||||
UnittestProto.TestEmptyMessageWithExtensions.getDescriptor()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -81,18 +79,16 @@ public class DiscardUnknownFieldsTest {
|
||||
payload.copyTo(copied, 0);
|
||||
payload.copyTo(copied, messageSize);
|
||||
CodedInputStream input = CodedInputStream.newInstance(copied);
|
||||
{
|
||||
// Use DiscardUnknownFieldsParser to parse the first payload.
|
||||
int oldLimit = input.pushLimit(messageSize);
|
||||
Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(input);
|
||||
assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
|
||||
input.popLimit(oldLimit);
|
||||
}
|
||||
{
|
||||
// Use the normal parser to parse the remaining payload should have unknown fields preserved.
|
||||
Message parsed = message.getParserForType().parseFrom(input);
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
}
|
||||
|
||||
// Use DiscardUnknownFieldsParser to parse the first payload.
|
||||
int oldLimit = input.pushLimit(messageSize);
|
||||
Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(input);
|
||||
assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
|
||||
input.popLimit(oldLimit);
|
||||
|
||||
// Use the normal parser to parse the remaining payload should have unknown fields preserved.
|
||||
parsed = message.getParserForType().parseFrom(input);
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,34 +100,18 @@ public class DiscardUnknownFieldsTest {
|
||||
UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
|
||||
Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
|
||||
assertEquals(message.getClass().getName(), payload, built.toByteString());
|
||||
|
||||
}
|
||||
/**
|
||||
* {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
|
||||
* Message.Builder#mergeUnknownFields(UnknownFieldSet)} should discard the unknown fields.
|
||||
*/
|
||||
private static void assertUnknownFieldsInUnknownFieldSetAreDiscarded(Message message)
|
||||
throws Exception {
|
||||
UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
|
||||
Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
|
||||
assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
|
||||
}
|
||||
|
||||
private static void assertUnknownFieldsPreserved(MessageLite message) throws Exception {
|
||||
{
|
||||
MessageLite parsed = message.getParserForType().parseFrom(payload);
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
}
|
||||
MessageLite parsed = message.getParserForType().parseFrom(payload);
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
|
||||
{
|
||||
MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
}
|
||||
parsed = message.newBuilderForType().mergeFrom(payload).build();
|
||||
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
|
||||
}
|
||||
|
||||
private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
|
||||
Message parsed =
|
||||
DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
|
||||
Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
|
||||
assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
|
||||
}
|
||||
|
||||
|
@ -45,10 +45,8 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class DoubleArrayListTest extends TestCase {
|
||||
|
||||
private static final DoubleArrayList UNARY_LIST =
|
||||
newImmutableDoubleArrayList(1);
|
||||
private static final DoubleArrayList TERTIARY_LIST =
|
||||
newImmutableDoubleArrayList(1, 2, 3);
|
||||
private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
|
||||
private static final DoubleArrayList TERTIARY_LIST = newImmutableDoubleArrayList(1, 2, 3);
|
||||
|
||||
private DoubleArrayList list;
|
||||
|
||||
@ -225,9 +223,7 @@ public class DoubleArrayListTest extends TestCase {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
list.add(Double.valueOf(5 + i));
|
||||
}
|
||||
assertEquals(
|
||||
asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D),
|
||||
list);
|
||||
assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list);
|
||||
|
||||
try {
|
||||
list.add(-1, 5D);
|
||||
@ -299,16 +295,14 @@ public class DoubleArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testRemoveEndOfCapacity() {
|
||||
DoubleList toRemove =
|
||||
DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addDouble(3);
|
||||
toRemove.remove(0);
|
||||
assertEquals(0, toRemove.size());
|
||||
}
|
||||
|
||||
public void testSublistRemoveEndOfCapacity() {
|
||||
DoubleList toRemove =
|
||||
DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addDouble(3);
|
||||
toRemove.subList(0, 1).clear();
|
||||
assertEquals(0, toRemove.size());
|
||||
|
@ -41,32 +41,30 @@ import java.util.Arrays;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which
|
||||
* tests some {@link DynamicMessage} functionality.
|
||||
* Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which tests some {@link
|
||||
* DynamicMessage} functionality.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class DynamicMessageTest extends TestCase {
|
||||
TestUtil.ReflectionTester reflectionTester =
|
||||
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
|
||||
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
|
||||
|
||||
TestUtil.ReflectionTester extensionsReflectionTester =
|
||||
new TestUtil.ReflectionTester(
|
||||
TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
|
||||
TestUtil.ReflectionTester packedReflectionTester =
|
||||
new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
|
||||
new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
|
||||
|
||||
public void testDynamicMessageAccessors() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.setAllFieldsViaReflection(builder);
|
||||
Message message = builder.build();
|
||||
reflectionTester.assertAllFieldsSetViaReflection(message);
|
||||
}
|
||||
|
||||
public void testSettersAfterBuild() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message firstMessage = builder.build();
|
||||
// double build()
|
||||
builder.build();
|
||||
@ -85,12 +83,12 @@ public class DynamicMessageTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testUnknownFields() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
|
||||
builder.setUnknownFields(UnknownFieldSet.newBuilder()
|
||||
.addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
|
||||
.addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
|
||||
.build());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
|
||||
builder.setUnknownFields(
|
||||
UnknownFieldSet.newBuilder()
|
||||
.addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
|
||||
.addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
|
||||
.build());
|
||||
Message message = builder.build();
|
||||
assertEquals(2, message.getUnknownFields().asMap().size());
|
||||
// clone() with unknown fields
|
||||
@ -105,8 +103,7 @@ public class DynamicMessageTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testDynamicMessageSettersRejectNull() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.assertReflectionSettersRejectNull(builder);
|
||||
}
|
||||
|
||||
@ -114,22 +111,19 @@ public class DynamicMessageTest extends TestCase {
|
||||
// We don't need to extensively test DynamicMessage's handling of
|
||||
// extensions because, frankly, it doesn't do anything special with them.
|
||||
// It treats them just like any other fields.
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
|
||||
extensionsReflectionTester.setAllFieldsViaReflection(builder);
|
||||
Message message = builder.build();
|
||||
extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
|
||||
}
|
||||
|
||||
public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
|
||||
extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
|
||||
}
|
||||
|
||||
public void testDynamicMessageRepeatedSetters() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.setAllFieldsViaReflection(builder);
|
||||
reflectionTester.modifyRepeatedFieldsViaReflection(builder);
|
||||
Message message = builder.build();
|
||||
@ -137,33 +131,29 @@ public class DynamicMessageTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
|
||||
}
|
||||
|
||||
public void testDynamicMessageDefaults() throws Exception {
|
||||
reflectionTester.assertClearViaReflection(
|
||||
DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
|
||||
DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
|
||||
reflectionTester.assertClearViaReflection(
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
|
||||
}
|
||||
|
||||
public void testDynamicMessageSerializedSize() throws Exception {
|
||||
TestAllTypes message = TestUtil.getAllSet();
|
||||
|
||||
Message.Builder dynamicBuilder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder dynamicBuilder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
|
||||
Message dynamicMessage = dynamicBuilder.build();
|
||||
|
||||
assertEquals(message.getSerializedSize(),
|
||||
dynamicMessage.getSerializedSize());
|
||||
assertEquals(message.getSerializedSize(), dynamicMessage.getSerializedSize());
|
||||
}
|
||||
|
||||
public void testDynamicMessageSerialization() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.setAllFieldsViaReflection(builder);
|
||||
Message message = builder.build();
|
||||
|
||||
@ -183,8 +173,7 @@ public class DynamicMessageTest extends TestCase {
|
||||
|
||||
ByteString rawBytes = message.toByteString();
|
||||
|
||||
Message message2 =
|
||||
DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
|
||||
Message message2 = DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
|
||||
reflectionTester.assertAllFieldsSetViaReflection(message2);
|
||||
|
||||
// Test Parser interface.
|
||||
@ -200,14 +189,13 @@ public class DynamicMessageTest extends TestCase {
|
||||
extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
|
||||
|
||||
// Test Parser interface.
|
||||
Message message2 = message.getParserForType().parseFrom(
|
||||
rawBytes, TestUtil.getExtensionRegistry());
|
||||
Message message2 =
|
||||
message.getParserForType().parseFrom(rawBytes, TestUtil.getExtensionRegistry());
|
||||
extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
|
||||
}
|
||||
|
||||
public void testDynamicMessagePackedSerialization() throws Exception {
|
||||
Message.Builder builder =
|
||||
DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
|
||||
Message.Builder builder = DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
|
||||
packedReflectionTester.setPackedFieldsViaReflection(builder);
|
||||
Message message = builder.build();
|
||||
|
||||
@ -227,8 +215,7 @@ public class DynamicMessageTest extends TestCase {
|
||||
|
||||
ByteString rawBytes = message.toByteString();
|
||||
|
||||
Message message2 =
|
||||
DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
|
||||
Message message2 = DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
|
||||
packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
|
||||
|
||||
// Test Parser interface.
|
||||
@ -245,41 +232,38 @@ public class DynamicMessageTest extends TestCase {
|
||||
reflectionTester.assertAllFieldsSetViaReflection(copy);
|
||||
|
||||
// Test oneof behavior
|
||||
FieldDescriptor bytesField =
|
||||
TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
|
||||
FieldDescriptor uint32Field =
|
||||
TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
|
||||
FieldDescriptor bytesField = TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
|
||||
FieldDescriptor uint32Field = TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
|
||||
assertTrue(copy.hasField(bytesField));
|
||||
assertFalse(copy.hasField(uint32Field));
|
||||
DynamicMessage copy2 =
|
||||
DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
|
||||
DynamicMessage copy2 = DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
|
||||
assertFalse(copy2.hasField(bytesField));
|
||||
assertTrue(copy2.hasField(uint32Field));
|
||||
assertEquals(123, copy2.getField(uint32Field));
|
||||
}
|
||||
|
||||
public void testToBuilder() throws Exception {
|
||||
DynamicMessage.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
reflectionTester.setAllFieldsViaReflection(builder);
|
||||
int unknownFieldNum = 9;
|
||||
long unknownFieldVal = 90;
|
||||
builder.setUnknownFields(UnknownFieldSet.newBuilder()
|
||||
.addField(unknownFieldNum,
|
||||
UnknownFieldSet.Field.newBuilder()
|
||||
.addVarint(unknownFieldVal).build())
|
||||
.build());
|
||||
builder.setUnknownFields(
|
||||
UnknownFieldSet.newBuilder()
|
||||
.addField(
|
||||
unknownFieldNum,
|
||||
UnknownFieldSet.Field.newBuilder().addVarint(unknownFieldVal).build())
|
||||
.build());
|
||||
DynamicMessage message = builder.build();
|
||||
|
||||
DynamicMessage derived = message.toBuilder().build();
|
||||
reflectionTester.assertAllFieldsSetViaReflection(derived);
|
||||
assertEquals(Arrays.asList(unknownFieldVal),
|
||||
assertEquals(
|
||||
Arrays.asList(unknownFieldVal),
|
||||
derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
|
||||
}
|
||||
|
||||
public void testDynamicOneofMessage() throws Exception {
|
||||
DynamicMessage.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
|
||||
assertFalse(builder.hasOneof(oneof));
|
||||
assertSame(null, builder.getOneofFieldDescriptor(oneof));
|
||||
@ -292,8 +276,7 @@ public class DynamicMessageTest extends TestCase {
|
||||
DynamicMessage message = builder.buildPartial();
|
||||
assertTrue(message.hasOneof(oneof));
|
||||
|
||||
DynamicMessage.Builder mergedBuilder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
DynamicMessage.Builder mergedBuilder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
FieldDescriptor mergedField = oneof.getField(0);
|
||||
mergedBuilder.setField(mergedField, 123);
|
||||
assertTrue(mergedBuilder.hasField(mergedField));
|
||||
@ -310,15 +293,12 @@ public class DynamicMessageTest extends TestCase {
|
||||
// Regression test for a bug that makes setField() not work for repeated
|
||||
// enum fields.
|
||||
public void testSettersForRepeatedEnumField() throws Exception {
|
||||
DynamicMessage.Builder builder =
|
||||
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
|
||||
FieldDescriptor repeatedEnumField =
|
||||
TestAllTypes.getDescriptor().findFieldByName(
|
||||
"repeated_nested_enum");
|
||||
TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
|
||||
EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor();
|
||||
builder.setField(repeatedEnumField, enumDescriptor.getValues());
|
||||
DynamicMessage message = builder.build();
|
||||
assertEquals(
|
||||
enumDescriptor.getValues(), message.getField(repeatedEnumField));
|
||||
assertEquals(enumDescriptor.getValues(), message.getField(repeatedEnumField));
|
||||
}
|
||||
}
|
||||
|
@ -34,43 +34,43 @@ import com.google.protobuf.UnittestLite.ForeignEnumLite;
|
||||
import com.google.protobuf.UnittestLite.TestAllTypesLite;
|
||||
import protobuf_unittest.UnittestProto.ForeignEnum;
|
||||
import protobuf_unittest.UnittestProto.TestAllTypes;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class EnumTest extends TestCase {
|
||||
|
||||
|
||||
public void testForNumber() {
|
||||
ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber());
|
||||
assertEquals(ForeignEnum.FOREIGN_BAR, e);
|
||||
|
||||
e = ForeignEnum.forNumber(1000);
|
||||
assertEquals(null, e);
|
||||
assertNull(e);
|
||||
}
|
||||
|
||||
|
||||
public void testForNumber_oneof() {
|
||||
TestAllTypes.OneofFieldCase e = TestAllTypes.OneofFieldCase.forNumber(
|
||||
TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
|
||||
TestAllTypes.OneofFieldCase e =
|
||||
TestAllTypes.OneofFieldCase.forNumber(
|
||||
TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
|
||||
assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
|
||||
|
||||
e = TestAllTypes.OneofFieldCase.forNumber(1000);
|
||||
assertEquals(null, e);
|
||||
assertNull(e);
|
||||
}
|
||||
|
||||
|
||||
public void testForNumberLite() {
|
||||
ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber());
|
||||
assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e);
|
||||
|
||||
e = ForeignEnumLite.forNumber(1000);
|
||||
assertEquals(null, e);
|
||||
assertNull(e);
|
||||
}
|
||||
|
||||
|
||||
public void testForNumberLite_oneof() {
|
||||
TestAllTypesLite.OneofFieldCase e = TestAllTypesLite.OneofFieldCase.forNumber(
|
||||
TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
|
||||
TestAllTypesLite.OneofFieldCase e =
|
||||
TestAllTypesLite.OneofFieldCase.forNumber(
|
||||
TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
|
||||
assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
|
||||
|
||||
e = TestAllTypesLite.OneofFieldCase.forNumber(1000);
|
||||
assertEquals(null, e);
|
||||
assertNull(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,31 +47,31 @@ import junit.framework.TestSuite;
|
||||
* creates.
|
||||
*
|
||||
* <p>This test simulates the runtime behaviour of the ExtensionRegistryFactory by delegating test
|
||||
* definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of
|
||||
* which is executed using a custom ClassLoader, simulating the ProtoLite environment.
|
||||
* definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of which
|
||||
* is executed using a custom ClassLoader, simulating the ProtoLite environment.
|
||||
*
|
||||
* <p>The test mechanism employed here is based on the pattern in
|
||||
* {@code com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
|
||||
* <p>The test mechanism employed here is based on the pattern in {@code
|
||||
* com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
|
||||
*/
|
||||
public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
|
||||
// A classloader which blacklists some non-Lite classes.
|
||||
private static final ClassLoader LITE_CLASS_LOADER = getLiteOnlyClassLoader();
|
||||
|
||||
/**
|
||||
* Defines the set of test methods which will be run.
|
||||
*/
|
||||
/** Defines the set of test methods which will be run. */
|
||||
static interface RegistryTests {
|
||||
void testCreate();
|
||||
|
||||
void testEmpty();
|
||||
|
||||
void testIsFullRegistry();
|
||||
|
||||
void testAdd();
|
||||
|
||||
void testAdd_immutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test implementations for the non-Lite usage of ExtensionRegistryFactory.
|
||||
*/
|
||||
/** Test implementations for the non-Lite usage of ExtensionRegistryFactory. */
|
||||
public static class InnerTest implements RegistryTests {
|
||||
|
||||
@Override
|
||||
@ -108,20 +108,25 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
ExtensionRegistry fullRegistry1 = (ExtensionRegistry) registry1;
|
||||
ExtensionRegistry fullRegistry2 = (ExtensionRegistry) registry2;
|
||||
|
||||
assertTrue("Test is using a non-lite extension",
|
||||
assertTrue(
|
||||
"Test is using a non-lite extension",
|
||||
GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(
|
||||
NonNestedExtensionLite.nonNestedExtensionLite.getClass()));
|
||||
assertNull("Extension is not registered in masqueraded full registry",
|
||||
assertNull(
|
||||
"Extension is not registered in masqueraded full registry",
|
||||
fullRegistry1.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
|
||||
GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
|
||||
extension = registry1.findLiteExtensionByNumber(
|
||||
NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
|
||||
extension =
|
||||
registry1.findLiteExtensionByNumber(
|
||||
NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
|
||||
assertNotNull("Extension registered in lite registry", extension);
|
||||
|
||||
assertTrue("Test is using a non-lite extension",
|
||||
assertTrue(
|
||||
"Test is using a non-lite extension",
|
||||
GeneratedMessage.GeneratedExtension.class.isAssignableFrom(
|
||||
NonNestedExtension.nonNestedExtension.getClass()));
|
||||
assertNotNull("Extension is registered in masqueraded full registry",
|
||||
NonNestedExtension.nonNestedExtension.getClass()));
|
||||
assertNotNull(
|
||||
"Extension is registered in masqueraded full registry",
|
||||
fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
|
||||
}
|
||||
|
||||
@ -131,27 +136,29 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
try {
|
||||
NonNestedExtensionLite.registerAllExtensions(registry1);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {}
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
try {
|
||||
registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {}
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
|
||||
ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance().getUnmodifiable();
|
||||
try {
|
||||
NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {}
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
registry2.add(NonNestedExtension.nonNestedExtension);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {}
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test implementations for the Lite usage of ExtensionRegistryFactory.
|
||||
*/
|
||||
/** Test implementations for the Lite usage of ExtensionRegistryFactory. */
|
||||
public static final class InnerLiteTest implements RegistryTests {
|
||||
|
||||
@Override
|
||||
@ -180,8 +187,9 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
|
||||
NonNestedExtensionLite.registerAllExtensions(registry);
|
||||
GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
|
||||
extension = registry.findLiteExtensionByNumber(
|
||||
NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
|
||||
extension =
|
||||
registry.findLiteExtensionByNumber(
|
||||
NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
|
||||
assertNotNull("Extension is registered in Lite registry", extension);
|
||||
}
|
||||
|
||||
@ -191,13 +199,12 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
try {
|
||||
NonNestedExtensionLite.registerAllExtensions(registry);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {}
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a suite of tests which the JUnit3 runner retrieves by reflection.
|
||||
*/
|
||||
/** Defines a suite of tests which the JUnit3 runner retrieves by reflection. */
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
for (Method method : RegistryTests.class.getMethods()) {
|
||||
@ -235,8 +242,8 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a custom ClassLoader blacklisting the classes which are inspected in the SUT
|
||||
* to determine the Lite/non-Lite runtime.
|
||||
* Constructs a custom ClassLoader blacklisting the classes which are inspected in the SUT to
|
||||
* determine the Lite/non-Lite runtime.
|
||||
*/
|
||||
private static ClassLoader getLiteOnlyClassLoader() {
|
||||
ClassLoader testClassLoader = ExtensionRegistryFactoryTest.class.getClassLoader();
|
||||
@ -250,8 +257,8 @@ public class ExtensionRegistryFactoryTest extends TestCase {
|
||||
// Construct a URLClassLoader delegating to the system ClassLoader, and looking up classes
|
||||
// in jar files based on the URLs already configured for this test's UrlClassLoader.
|
||||
// Certain classes throw a ClassNotFoundException by design.
|
||||
return new URLClassLoader(((URLClassLoader) testClassLoader).getURLs(),
|
||||
ClassLoader.getSystemClassLoader()) {
|
||||
return new URLClassLoader(
|
||||
((URLClassLoader) testClassLoader).getURLs(), ClassLoader.getSystemClassLoader()) {
|
||||
@Override
|
||||
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (classNamesNotInLite.contains(name)) {
|
||||
|
@ -38,12 +38,10 @@ 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.
|
||||
* 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) {
|
||||
@ -59,9 +57,7 @@ public class FieldPresenceTest extends TestCase {
|
||||
}
|
||||
|
||||
private static void assertHasMethodRemoved(
|
||||
Class<?> classWithFieldPresence,
|
||||
Class<?> classWithoutFieldPresence,
|
||||
String camelName) {
|
||||
Class<?> classWithFieldPresence, Class<?> classWithoutFieldPresence, String camelName) {
|
||||
assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
|
||||
assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
|
||||
assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
|
||||
@ -70,72 +66,38 @@ public class FieldPresenceTest extends TestCase {
|
||||
|
||||
public void testHasMethod() {
|
||||
// Optional non-message fields don't have a hasFoo() method generated.
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalInt32");
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalString");
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalBytes");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OptionalInt32");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OptionalString");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OptionalBytes");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OptionalNestedEnum");
|
||||
UnittestProto.TestAllTypes.class, TestAllTypes.class, "OptionalNestedEnum");
|
||||
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OptionalInt32");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OptionalInt32");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OptionalString");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OptionalString");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OptionalBytes");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OptionalBytes");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OptionalNestedEnum");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OptionalNestedEnum");
|
||||
|
||||
// message fields still have the hasFoo() method generated.
|
||||
assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
|
||||
assertFalse(TestAllTypes.getDefaultInstance().hasOptionalNestedMessage());
|
||||
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
|
||||
|
||||
// oneof fields don't have hasFoo() methods for non-message types.
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OneofUint32");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OneofString");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.class,
|
||||
TestAllTypes.class,
|
||||
"OneofBytes");
|
||||
assertFalse(TestAllTypes.newBuilder().build().hasOneofNestedMessage());
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofUint32");
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofString");
|
||||
assertHasMethodRemoved(UnittestProto.TestAllTypes.class, TestAllTypes.class, "OneofBytes");
|
||||
assertFalse(TestAllTypes.getDefaultInstance().hasOneofNestedMessage());
|
||||
assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
|
||||
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OneofUint32");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofUint32");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OneofString");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofString");
|
||||
assertHasMethodRemoved(
|
||||
UnittestProto.TestAllTypes.Builder.class,
|
||||
TestAllTypes.Builder.class,
|
||||
"OneofBytes");
|
||||
UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofBytes");
|
||||
}
|
||||
|
||||
public void testOneofEquals() throws Exception {
|
||||
@ -200,10 +162,10 @@ public class FieldPresenceTest extends TestCase {
|
||||
assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
|
||||
|
||||
// equals()/hashCode() should produce the same results.
|
||||
TestAllTypes empty = TestAllTypes.newBuilder().build();
|
||||
TestAllTypes empty = TestAllTypes.getDefaultInstance();
|
||||
message = builder.build();
|
||||
assertTrue(empty.equals(message));
|
||||
assertTrue(message.equals(empty));
|
||||
assertEquals(message, empty);
|
||||
assertEquals(empty, message);
|
||||
assertEquals(empty.hashCode(), message.hashCode());
|
||||
}
|
||||
|
||||
@ -215,7 +177,7 @@ public class FieldPresenceTest extends TestCase {
|
||||
FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
|
||||
|
||||
// Field not present.
|
||||
TestAllTypes message = TestAllTypes.newBuilder().build();
|
||||
TestAllTypes message = TestAllTypes.getDefaultInstance();
|
||||
assertFalse(message.hasField(optionalInt32Field));
|
||||
assertFalse(message.hasField(optionalStringField));
|
||||
assertFalse(message.hasField(optionalBytesField));
|
||||
@ -223,12 +185,13 @@ public class FieldPresenceTest extends TestCase {
|
||||
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();
|
||||
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));
|
||||
@ -236,12 +199,13 @@ public class FieldPresenceTest extends TestCase {
|
||||
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();
|
||||
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));
|
||||
@ -284,7 +248,9 @@ public class FieldPresenceTest extends TestCase {
|
||||
assertEquals(4, message.getAllFields().size());
|
||||
|
||||
// Field set to default value is seen as not present.
|
||||
message = message.toBuilder()
|
||||
message =
|
||||
message
|
||||
.toBuilder()
|
||||
.setField(optionalInt32Field, 0)
|
||||
.setField(optionalStringField, "")
|
||||
.setField(optionalBytesField, ByteString.EMPTY)
|
||||
@ -302,8 +268,7 @@ public class FieldPresenceTest extends TestCase {
|
||||
assertFalse(builder.hasOptionalNestedMessage());
|
||||
assertFalse(builder.build().hasOptionalNestedMessage());
|
||||
|
||||
TestAllTypes.NestedMessage.Builder nestedBuilder =
|
||||
builder.getOptionalNestedMessageBuilder();
|
||||
TestAllTypes.NestedMessage.Builder nestedBuilder = builder.getOptionalNestedMessageBuilder();
|
||||
assertTrue(builder.hasOptionalNestedMessage());
|
||||
assertTrue(builder.build().hasOptionalNestedMessage());
|
||||
|
||||
@ -341,8 +306,7 @@ public class FieldPresenceTest extends TestCase {
|
||||
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());
|
||||
assertEquals(TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase());
|
||||
}
|
||||
|
||||
// Regression test for b/16173397
|
||||
@ -376,8 +340,7 @@ public class FieldPresenceTest extends TestCase {
|
||||
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
|
||||
|
||||
// Test optional proto2 message fields.
|
||||
UnittestProto.TestRequired.Builder proto2Builder =
|
||||
builder.getOptionalProto2MessageBuilder();
|
||||
UnittestProto.TestRequired.Builder proto2Builder = builder.getOptionalProto2MessageBuilder();
|
||||
assertFalse(builder.isInitialized());
|
||||
assertFalse(builder.buildPartial().isInitialized());
|
||||
|
||||
|
@ -45,10 +45,8 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class FloatArrayListTest extends TestCase {
|
||||
|
||||
private static final FloatArrayList UNARY_LIST =
|
||||
newImmutableFloatArrayList(1);
|
||||
private static final FloatArrayList TERTIARY_LIST =
|
||||
newImmutableFloatArrayList(1, 2, 3);
|
||||
private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
|
||||
private static final FloatArrayList TERTIARY_LIST = newImmutableFloatArrayList(1, 2, 3);
|
||||
|
||||
private FloatArrayList list;
|
||||
|
||||
@ -225,9 +223,7 @@ public class FloatArrayListTest extends TestCase {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
list.add(Float.valueOf(5 + i));
|
||||
}
|
||||
assertEquals(
|
||||
asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F),
|
||||
list);
|
||||
assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list);
|
||||
|
||||
try {
|
||||
list.add(-1, 5F);
|
||||
@ -299,16 +295,14 @@ public class FloatArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testRemoveEndOfCapacity() {
|
||||
FloatList toRemove =
|
||||
FloatArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addFloat(3);
|
||||
toRemove.remove(0);
|
||||
assertEquals(0, toRemove.size());
|
||||
}
|
||||
|
||||
public void testSublistRemoveEndOfCapacity() {
|
||||
FloatList toRemove =
|
||||
FloatArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addFloat(3);
|
||||
toRemove.subList(0, 1).clear();
|
||||
assertEquals(0, toRemove.size());
|
||||
|
@ -31,11 +31,10 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* A prerun for a test suite that allows running the full protocol buffer
|
||||
* tests in a mode that disables the optimization for not using
|
||||
* {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are
|
||||
* requested. This allows us to run all the tests through both code paths
|
||||
* and ensures that both code paths produce identical results.
|
||||
* A prerun for a test suite that allows running the full protocol buffer tests in a mode that
|
||||
* disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
|
||||
* SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
|
||||
* code paths and ensures that both code paths produce identical results.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,10 +45,8 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class IntArrayListTest extends TestCase {
|
||||
|
||||
private static final IntArrayList UNARY_LIST =
|
||||
newImmutableIntArrayList(1);
|
||||
private static final IntArrayList TERTIARY_LIST =
|
||||
newImmutableIntArrayList(1, 2, 3);
|
||||
private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
|
||||
private static final IntArrayList TERTIARY_LIST = newImmutableIntArrayList(1, 2, 3);
|
||||
|
||||
private IntArrayList list;
|
||||
|
||||
@ -225,9 +223,7 @@ public class IntArrayListTest extends TestCase {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
list.add(Integer.valueOf(5 + i));
|
||||
}
|
||||
assertEquals(
|
||||
asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10),
|
||||
list);
|
||||
assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
|
||||
|
||||
try {
|
||||
list.add(-1, 5);
|
||||
@ -299,16 +295,14 @@ public class IntArrayListTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testRemoveEndOfCapacity() {
|
||||
IntList toRemove =
|
||||
IntArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addInt(3);
|
||||
toRemove.remove(0);
|
||||
assertEquals(0, toRemove.size());
|
||||
}
|
||||
|
||||
public void testSublistRemoveEndOfCapacity() {
|
||||
IntList toRemove =
|
||||
IntArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
|
||||
toRemove.addInt(3);
|
||||
toRemove.subList(0, 1).clear();
|
||||
assertEquals(0, toRemove.size());
|
||||
|
@ -39,45 +39,36 @@ import static com.google.protobuf.IsValidUtf8TestUtil.testBytes;
|
||||
|
||||
import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
|
||||
import com.google.protobuf.IsValidUtf8TestUtil.Shard;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link ByteString#isValidUtf8()}. This includes three
|
||||
* brute force tests that actually test every permutation of one byte, two byte,
|
||||
* and three byte sequences to ensure that the method produces the right result
|
||||
* for every possible byte encoding where "right" means it's consistent with
|
||||
* java's UTF-8 string encoding/decoding such that the method returns true for
|
||||
* any sequence that will round trip when converted to a String and then back to
|
||||
* bytes and will return false for any sequence that will not round trip.
|
||||
* See also {@link IsValidUtf8FourByteTest}. It also includes some
|
||||
* other more targeted tests.
|
||||
* Tests cases for {@link ByteString#isValidUtf8()}. This includes three brute force tests that
|
||||
* actually test every permutation of one byte, two byte, and three byte sequences to ensure that
|
||||
* the method produces the right result for every possible byte encoding where "right" means it's
|
||||
* consistent with java's UTF-8 string encoding/decoding such that the method returns true for any
|
||||
* sequence that will round trip when converted to a String and then back to bytes and will return
|
||||
* false for any sequence that will not round trip. See also {@link IsValidUtf8FourByteTest}. It
|
||||
* also includes some other more targeted tests.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
* @author martinrb@google.com (Martin Buchholz)
|
||||
*/
|
||||
public class IsValidUtf8Test extends TestCase {
|
||||
/**
|
||||
* Tests that round tripping of all two byte permutations work.
|
||||
*/
|
||||
/** Tests that round tripping of all two byte permutations work. */
|
||||
public void testIsValidUtf8_1Byte() {
|
||||
testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that round tripping of all two byte permutations work.
|
||||
*/
|
||||
/** Tests that round tripping of all two byte permutations work. */
|
||||
public void testIsValidUtf8_2Bytes() {
|
||||
testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that round tripping of all three byte permutations work.
|
||||
*/
|
||||
/** Tests that round tripping of all three byte permutations work. */
|
||||
public void testIsValidUtf8_3Bytes() {
|
||||
// Travis' OOM killer doesn't like this test
|
||||
if (System.getenv("TRAVIS") == null) {
|
||||
@ -88,10 +79,9 @@ public class IsValidUtf8Test extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that round tripping of a sample of four byte permutations work.
|
||||
* All permutations are prohibitively expensive to test for automated runs;
|
||||
* {@link IsValidUtf8FourByteTest} is used for full coverage. This method
|
||||
* tests specific four-byte cases.
|
||||
* Tests that round tripping of a sample of four byte permutations work. All permutations are
|
||||
* prohibitively expensive to test for automated runs; {@link IsValidUtf8FourByteTest} is used for
|
||||
* full coverage. This method tests specific four-byte cases.
|
||||
*/
|
||||
public void testIsValidUtf8_4BytesSamples() {
|
||||
// Valid 4 byte.
|
||||
@ -106,9 +96,7 @@ public class IsValidUtf8Test extends TestCase {
|
||||
assertInvalidUtf8(0xF4, 0x90, 0xAD, 0xA2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests some hard-coded test cases.
|
||||
*/
|
||||
/** Tests some hard-coded test cases. */
|
||||
public void testSomeSequences() {
|
||||
// Empty
|
||||
assertTrue(asBytes("").isValidUtf8());
|
||||
@ -149,11 +137,12 @@ public class IsValidUtf8Test extends TestCase {
|
||||
assertTrue(not ^ leaf.isValidUtf8());
|
||||
assertTrue(not ^ sub.isValidUtf8());
|
||||
ByteString[] ropes = {
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
|
||||
RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(sub, leaf)};
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
|
||||
RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
|
||||
RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
|
||||
RopeByteString.newInstanceForTest(sub, leaf)
|
||||
};
|
||||
for (ByteString rope : ropes) {
|
||||
assertTrue(not ^ rope.isValidUtf8());
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ import java.util.Random;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Shared testing code for {@link IsValidUtf8Test} and
|
||||
* {@link IsValidUtf8FourByteTest}.
|
||||
* Shared testing code for {@link IsValidUtf8Test} and {@link IsValidUtf8FourByteTest}.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
* @author martinrb@google.com (Martin Buchholz)
|
||||
@ -65,44 +64,47 @@ final class IsValidUtf8TestUtil {
|
||||
ByteString newByteString(byte[] bytes);
|
||||
}
|
||||
|
||||
static final ByteStringFactory LITERAL_FACTORY = new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
return ByteString.wrap(bytes);
|
||||
}
|
||||
};
|
||||
static final ByteStringFactory LITERAL_FACTORY =
|
||||
new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
return ByteString.wrap(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
static final ByteStringFactory HEAP_NIO_FACTORY = new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
return new NioByteString(ByteBuffer.wrap(bytes));
|
||||
}
|
||||
};
|
||||
static final ByteStringFactory HEAP_NIO_FACTORY =
|
||||
new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
return new NioByteString(ByteBuffer.wrap(bytes));
|
||||
}
|
||||
};
|
||||
|
||||
private static ThreadLocal<SoftReference<ByteBuffer>> directBuffer =
|
||||
new ThreadLocal<SoftReference<ByteBuffer>>();
|
||||
|
||||
/**
|
||||
* Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this
|
||||
* uses a thread local direct buffer. This means that each call will overwrite the buffer's
|
||||
* contents from the previous call, so the calling code must be careful not to continue using
|
||||
* a buffer returned from a previous invocation.
|
||||
* Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this uses a
|
||||
* thread local direct buffer. This means that each call will overwrite the buffer's contents from
|
||||
* the previous call, so the calling code must be careful not to continue using a buffer returned
|
||||
* from a previous invocation.
|
||||
*/
|
||||
static final ByteStringFactory DIRECT_NIO_FACTORY = new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
SoftReference<ByteBuffer> ref = directBuffer.get();
|
||||
ByteBuffer buffer = ref == null ? null : ref.get();
|
||||
if (buffer == null || buffer.capacity() < bytes.length) {
|
||||
buffer = ByteBuffer.allocateDirect(bytes.length);
|
||||
directBuffer.set(new SoftReference<ByteBuffer>(buffer));
|
||||
}
|
||||
buffer.clear();
|
||||
buffer.put(bytes);
|
||||
buffer.flip();
|
||||
return new NioByteString(buffer);
|
||||
}
|
||||
};
|
||||
static final ByteStringFactory DIRECT_NIO_FACTORY =
|
||||
new ByteStringFactory() {
|
||||
@Override
|
||||
public ByteString newByteString(byte[] bytes) {
|
||||
SoftReference<ByteBuffer> ref = directBuffer.get();
|
||||
ByteBuffer buffer = ref == null ? null : ref.get();
|
||||
if (buffer == null || buffer.capacity() < bytes.length) {
|
||||
buffer = ByteBuffer.allocateDirect(bytes.length);
|
||||
directBuffer.set(new SoftReference<ByteBuffer>(buffer));
|
||||
}
|
||||
buffer.clear();
|
||||
buffer.put(bytes);
|
||||
buffer.flip();
|
||||
return new NioByteString(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
// 128 - [chars 0x0000 to 0x007f]
|
||||
static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
|
||||
@ -116,9 +118,10 @@ final class IsValidUtf8TestUtil {
|
||||
// 18,304
|
||||
static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
|
||||
// Both bytes are one byte characters
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
|
||||
// The possible number of two byte characters
|
||||
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2)
|
||||
+
|
||||
// The possible number of two byte characters
|
||||
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
|
||||
// 2048
|
||||
static final long THREE_BYTE_SURROGATES = 2 * 1024;
|
||||
@ -130,11 +133,13 @@ final class IsValidUtf8TestUtil {
|
||||
// 2,650,112
|
||||
static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
|
||||
// All one byte characters
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
|
||||
// One two byte character and a one byte character
|
||||
2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
|
||||
// Three byte characters
|
||||
THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3)
|
||||
+
|
||||
// One two byte character and a one byte character
|
||||
2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
+
|
||||
// Three byte characters
|
||||
THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
|
||||
// 1,048,576 [chars 0x10000L to 0x10FFFF]
|
||||
static final long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
|
||||
@ -142,17 +147,22 @@ final class IsValidUtf8TestUtil {
|
||||
// 289,571,839
|
||||
static final long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
|
||||
// All one byte characters
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
|
||||
// One and three byte characters
|
||||
2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
|
||||
// Two two byte characters
|
||||
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
|
||||
// Permutations of one and two byte characters
|
||||
3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
* ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
+
|
||||
// Four byte characters
|
||||
FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4)
|
||||
+
|
||||
// One and three byte characters
|
||||
2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
+
|
||||
// Two two byte characters
|
||||
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
+
|
||||
// Permutations of one and two byte characters
|
||||
3
|
||||
* TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
* ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
* ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
|
||||
+
|
||||
// Four byte characters
|
||||
FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
|
||||
|
||||
static final class Shard {
|
||||
final long index;
|
||||
@ -160,7 +170,6 @@ final class IsValidUtf8TestUtil {
|
||||
final long lim;
|
||||
final long expected;
|
||||
|
||||
|
||||
public Shard(long index, long start, long lim, long expected) {
|
||||
assertTrue(start < lim);
|
||||
this.index = index;
|
||||
@ -206,7 +215,6 @@ final class IsValidUtf8TestUtil {
|
||||
static final List<Shard> FOUR_BYTE_SHARDS =
|
||||
generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
|
||||
|
||||
|
||||
private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
|
||||
assertEquals(numShards, expected.length);
|
||||
List<Shard> shards = new ArrayList<Shard>(numShards);
|
||||
@ -220,8 +228,7 @@ final class IsValidUtf8TestUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to run the loop to test all the permutations for the number of bytes
|
||||
* specified.
|
||||
* Helper to run the loop to test all the permutations for the number of bytes specified.
|
||||
*
|
||||
* @param factory the factory for {@link ByteString} instances.
|
||||
* @param numBytes the number of bytes in the byte array
|
||||
@ -232,16 +239,15 @@ final class IsValidUtf8TestUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to run the loop to test all the permutations for the number of bytes
|
||||
* specified. This overload is useful for debugging to get the loop to start
|
||||
* at a certain character.
|
||||
* Helper to run the loop to test all the permutations for the number of bytes specified. This
|
||||
* overload is useful for debugging to get the loop to start at a certain character.
|
||||
*
|
||||
* @param factory the factory for {@link ByteString} instances.
|
||||
* @param numBytes the number of bytes in the byte array
|
||||
* @param expectedCount the expected number of roundtrippable permutations
|
||||
* @param start the starting bytes encoded as a long as big-endian
|
||||
* @param lim the limit of bytes to process encoded as a long as big-endian,
|
||||
* or -1 to mean the max limit for numBytes
|
||||
* @param lim the limit of bytes to process encoded as a long as big-endian, or -1 to mean the max
|
||||
* limit for numBytes
|
||||
*/
|
||||
static void testBytes(
|
||||
ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
|
||||
@ -301,9 +307,10 @@ final class IsValidUtf8TestUtil {
|
||||
assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
|
||||
|
||||
// Test ropes built out of small partial sequences
|
||||
ByteString rope = RopeByteString.newInstanceForTest(
|
||||
bs.substring(0, i),
|
||||
RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
|
||||
ByteString rope =
|
||||
RopeByteString.newInstanceForTest(
|
||||
bs.substring(0, i),
|
||||
RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
|
||||
assertSame(RopeByteString.class, rope.getClass());
|
||||
|
||||
ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
|
||||
@ -336,27 +343,28 @@ final class IsValidUtf8TestUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of {@link #testBytes} that does less allocation using the
|
||||
* low-level encoders/decoders directly. Checked in because it's useful for
|
||||
* debugging when trying to process bytes faster, but since it doesn't use the
|
||||
* actual String class, it's possible for incompatibilities to develop
|
||||
* Variation of {@link #testBytes} that does less allocation using the low-level encoders/decoders
|
||||
* directly. Checked in because it's useful for debugging when trying to process bytes faster, but
|
||||
* since it doesn't use the actual String class, it's possible for incompatibilities to develop
|
||||
* (although unlikely).
|
||||
*
|
||||
* @param factory the factory for {@link ByteString} instances.
|
||||
* @param numBytes the number of bytes in the byte array
|
||||
* @param expectedCount the expected number of roundtrippable permutations
|
||||
* @param start the starting bytes encoded as a long as big-endian
|
||||
* @param lim the limit of bytes to process encoded as a long as big-endian,
|
||||
* or -1 to mean the max limit for numBytes
|
||||
* @param lim the limit of bytes to process encoded as a long as big-endian, or -1 to mean the max
|
||||
* limit for numBytes
|
||||
*/
|
||||
static void testBytesUsingByteBuffers(
|
||||
ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
|
||||
CharsetDecoder decoder =
|
||||
Internal.UTF_8.newDecoder()
|
||||
Internal.UTF_8
|
||||
.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
CharsetEncoder encoder =
|
||||
Internal.UTF_8.newEncoder()
|
||||
Internal.UTF_8
|
||||
.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
byte[] bytes = new byte[numBytes];
|
||||
@ -434,8 +442,10 @@ final class IsValidUtf8TestUtil {
|
||||
}
|
||||
|
||||
private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) {
|
||||
fail("Failure: (" + Long.toHexString(byteChar) + ") " + toHexString(bytes) + " => "
|
||||
+ toHexString(after, len));
|
||||
fail(
|
||||
String.format(
|
||||
"Failure: (%s) %s => %s",
|
||||
Long.toHexString(byteChar), toHexString(bytes), toHexString(after, len)));
|
||||
}
|
||||
|
||||
private static String toHexString(byte[] b) {
|
||||
|
@ -42,8 +42,7 @@ import junit.framework.TestCase;
|
||||
public class LazyFieldTest extends TestCase {
|
||||
public void testHashCode() {
|
||||
MessageLite message = TestUtil.getAllSet();
|
||||
LazyField lazyField =
|
||||
createLazyFieldFromMessage(message);
|
||||
LazyField lazyField = createLazyFieldFromMessage(message);
|
||||
assertEquals(message.hashCode(), lazyField.hashCode());
|
||||
lazyField.getValue();
|
||||
assertEquals(message.hashCode(), lazyField.hashCode());
|
||||
@ -102,8 +101,8 @@ public class LazyFieldTest extends TestCase {
|
||||
|
||||
private LazyField createLazyFieldFromMessage(MessageLite message) {
|
||||
ByteString bytes = message.toByteString();
|
||||
return new LazyField(message.getDefaultInstanceForType(),
|
||||
TestUtil.getExtensionRegistry(), bytes);
|
||||
return new LazyField(
|
||||
message.getDefaultInstanceForType(), TestUtil.getExtensionRegistry(), bytes);
|
||||
}
|
||||
|
||||
private void changeValue(LazyField lazyField) {
|
||||
@ -114,7 +113,6 @@ public class LazyFieldTest extends TestCase {
|
||||
}
|
||||
|
||||
private void assertNotEqual(Object unexpected, Object actual) {
|
||||
assertFalse(unexpected == actual
|
||||
|| (unexpected != null && unexpected.equals(actual)));
|
||||
assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class LazyMessageLiteTest extends TestCase {
|
||||
|
||||
private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@ -57,19 +55,16 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSetValues() {
|
||||
LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
|
||||
.setNum(3)
|
||||
.build();
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(2)
|
||||
.setNested(nested)
|
||||
.build();
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.setNum(1)
|
||||
.setInner(inner)
|
||||
.setOneofNum(123)
|
||||
.setOneofInner(inner)
|
||||
.build();
|
||||
LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder().setNum(3).build();
|
||||
LazyInnerMessageLite inner =
|
||||
LazyInnerMessageLite.newBuilder().setNum(2).setNested(nested).build();
|
||||
LazyMessageLite outer =
|
||||
LazyMessageLite.newBuilder()
|
||||
.setNum(1)
|
||||
.setInner(inner)
|
||||
.setOneofNum(123)
|
||||
.setOneofInner(inner)
|
||||
.build();
|
||||
|
||||
assertEquals(1, outer.getNum());
|
||||
assertEquals(421, outer.getNumWithDefault());
|
||||
@ -90,44 +85,43 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSetRepeatedValues() {
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.setNum(1)
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
|
||||
.build();
|
||||
LazyMessageLite outer =
|
||||
LazyMessageLite.newBuilder()
|
||||
.setNum(1)
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
|
||||
.build();
|
||||
|
||||
assertEquals(1, outer.getNum());
|
||||
assertEquals(2, outer.getRepeatedInnerCount());
|
||||
assertEquals(119, outer.getRepeatedInner(0).getNum());
|
||||
assertEquals(122, outer.getRepeatedInner(1).getNum());
|
||||
}
|
||||
|
||||
|
||||
public void testRepeatedMutability() throws Exception {
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
|
||||
.build();
|
||||
|
||||
LazyMessageLite outer =
|
||||
LazyMessageLite.newBuilder()
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
|
||||
.build();
|
||||
|
||||
outer = LazyMessageLite.parseFrom(outer.toByteArray());
|
||||
try {
|
||||
outer.getRepeatedInnerList().set(1, null);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException expected) {}
|
||||
} catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddAll() {
|
||||
ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
|
||||
ArrayList<LazyInnerMessageLite> inners = new ArrayList<>();
|
||||
int count = 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(i)
|
||||
.build();
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().setNum(i).build();
|
||||
inners.add(inner);
|
||||
}
|
||||
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.addAllRepeatedInner(inners)
|
||||
.build();
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder().addAllRepeatedInner(inners).build();
|
||||
assertEquals(count, outer.getRepeatedInnerCount());
|
||||
for (int i = 0; i < count; i++) {
|
||||
assertEquals(i, outer.getRepeatedInner(i).getNum());
|
||||
@ -135,8 +129,7 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testGetDefaultValues() {
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.build();
|
||||
LazyMessageLite outer = LazyMessageLite.getDefaultInstance();
|
||||
|
||||
assertEquals(0, outer.getNum());
|
||||
assertEquals(421, outer.getNumWithDefault());
|
||||
@ -156,15 +149,12 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testClearValues() {
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(115)
|
||||
.build();
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().setNum(115).build();
|
||||
|
||||
LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
|
||||
|
||||
assertEquals(0, outerBuilder.build().getNum());
|
||||
|
||||
|
||||
// Set/Clear num
|
||||
outerBuilder.setNum(100);
|
||||
|
||||
@ -178,9 +168,9 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
assertEquals(421, outerBuilder.build().getNumWithDefault());
|
||||
assertFalse(outerBuilder.build().hasInner());
|
||||
|
||||
|
||||
// Set/Clear all
|
||||
outerBuilder.setNum(100)
|
||||
outerBuilder
|
||||
.setNum(100)
|
||||
.setInner(inner)
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
|
||||
.addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
|
||||
@ -210,23 +200,17 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testMergeValues() {
|
||||
LazyMessageLite outerBase = LazyMessageLite.newBuilder()
|
||||
.setNumWithDefault(122)
|
||||
.build();
|
||||
LazyMessageLite outerBase = LazyMessageLite.newBuilder().setNumWithDefault(122).build();
|
||||
|
||||
LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(115)
|
||||
.build();
|
||||
LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
|
||||
.setNum(119)
|
||||
.setInner(innerMerging)
|
||||
.setOneofInner(innerMerging)
|
||||
.build();
|
||||
LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder().setNum(115).build();
|
||||
LazyMessageLite outerMerging =
|
||||
LazyMessageLite.newBuilder()
|
||||
.setNum(119)
|
||||
.setInner(innerMerging)
|
||||
.setOneofInner(innerMerging)
|
||||
.build();
|
||||
|
||||
LazyMessageLite merged = LazyMessageLite
|
||||
.newBuilder(outerBase)
|
||||
.mergeFrom(outerMerging)
|
||||
.build();
|
||||
LazyMessageLite merged = LazyMessageLite.newBuilder(outerBase).mergeFrom(outerMerging).build();
|
||||
assertEquals(119, merged.getNum());
|
||||
assertEquals(122, merged.getNumWithDefault());
|
||||
assertEquals(115, merged.getInner().getNum());
|
||||
@ -236,23 +220,18 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testMergeDefaultValues() {
|
||||
LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(115)
|
||||
.build();
|
||||
LazyMessageLite outerBase = LazyMessageLite.newBuilder()
|
||||
.setNum(119)
|
||||
.setNumWithDefault(122)
|
||||
.setInner(innerBase)
|
||||
.setOneofInner(innerBase)
|
||||
.build();
|
||||
LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder().setNum(115).build();
|
||||
LazyMessageLite outerBase =
|
||||
LazyMessageLite.newBuilder()
|
||||
.setNum(119)
|
||||
.setNumWithDefault(122)
|
||||
.setInner(innerBase)
|
||||
.setOneofInner(innerBase)
|
||||
.build();
|
||||
|
||||
LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
|
||||
.build();
|
||||
LazyMessageLite outerMerging = LazyMessageLite.getDefaultInstance();
|
||||
|
||||
LazyMessageLite merged = LazyMessageLite
|
||||
.newBuilder(outerBase)
|
||||
.mergeFrom(outerMerging)
|
||||
.build();
|
||||
LazyMessageLite merged = LazyMessageLite.newBuilder(outerBase).mergeFrom(outerMerging).build();
|
||||
// Merging default-instance shouldn't overwrite values in the base message.
|
||||
assertEquals(119, merged.getNum());
|
||||
assertEquals(122, merged.getNumWithDefault());
|
||||
@ -264,7 +243,7 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
|
||||
// Regression test for b/28198805.
|
||||
public void testMergeOneofMessages() throws Exception {
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().build();
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.getDefaultInstance();
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder().setOneofInner(inner).build();
|
||||
ByteString data1 = outer.toByteString();
|
||||
|
||||
@ -280,18 +259,11 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSerialize() throws InvalidProtocolBufferException {
|
||||
LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
|
||||
.setNum(3)
|
||||
.build();
|
||||
LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
|
||||
.setNum(2)
|
||||
.setNested(nested)
|
||||
.build();
|
||||
LazyMessageLite outer = LazyMessageLite.newBuilder()
|
||||
.setNum(1)
|
||||
.setInner(inner)
|
||||
.setOneofInner(inner)
|
||||
.build();
|
||||
LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder().setNum(3).build();
|
||||
LazyInnerMessageLite inner =
|
||||
LazyInnerMessageLite.newBuilder().setNum(2).setNested(nested).build();
|
||||
LazyMessageLite outer =
|
||||
LazyMessageLite.newBuilder().setNum(1).setInner(inner).setOneofInner(inner).build();
|
||||
|
||||
ByteString bytes = outer.toByteString();
|
||||
assertEquals(bytes.size(), outer.getSerializedSize());
|
||||
@ -299,18 +271,18 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
|
||||
|
||||
assertEquals(1, deserialized.getNum());
|
||||
assertEquals(421, deserialized.getNumWithDefault());
|
||||
assertEquals(421, deserialized.getNumWithDefault());
|
||||
|
||||
assertEquals(2, deserialized.getInner().getNum());
|
||||
assertEquals(42, deserialized.getInner().getNumWithDefault());
|
||||
assertEquals(2, deserialized.getInner().getNum());
|
||||
assertEquals(42, deserialized.getInner().getNumWithDefault());
|
||||
|
||||
assertEquals(3, deserialized.getInner().getNested().getNum());
|
||||
assertEquals(4, deserialized.getInner().getNested().getNumWithDefault());
|
||||
assertEquals(3, deserialized.getInner().getNested().getNum());
|
||||
assertEquals(4, deserialized.getInner().getNested().getNumWithDefault());
|
||||
|
||||
assertEquals(2, deserialized.getOneofInner().getNum());
|
||||
assertEquals(42, deserialized.getOneofInner().getNumWithDefault());
|
||||
assertEquals(3, deserialized.getOneofInner().getNested().getNum());
|
||||
assertEquals(4, deserialized.getOneofInner().getNested().getNumWithDefault());
|
||||
assertEquals(2, deserialized.getOneofInner().getNum());
|
||||
assertEquals(42, deserialized.getOneofInner().getNumWithDefault());
|
||||
assertEquals(3, deserialized.getOneofInner().getNested().getNum());
|
||||
assertEquals(4, deserialized.getOneofInner().getNested().getNumWithDefault());
|
||||
|
||||
assertEquals(bytes, deserialized.toByteString());
|
||||
}
|
||||
@ -318,8 +290,7 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
public void testExtensions() throws Exception {
|
||||
LazyInnerMessageLite.Builder innerBuilder = LazyInnerMessageLite.newBuilder();
|
||||
innerBuilder.setExtension(
|
||||
LazyExtension.extension, LazyExtension.newBuilder()
|
||||
.setName("name").build());
|
||||
LazyExtension.extension, LazyExtension.newBuilder().setName("name").build());
|
||||
assertTrue(innerBuilder.hasExtension(LazyExtension.extension));
|
||||
assertEquals("name", innerBuilder.getExtension(LazyExtension.extension).getName());
|
||||
|
||||
@ -327,8 +298,7 @@ public class LazyMessageLiteTest extends TestCase {
|
||||
assertTrue(innerMessage.hasExtension(LazyExtension.extension));
|
||||
assertEquals("name", innerMessage.getExtension(LazyExtension.extension).getName());
|
||||
|
||||
LazyMessageLite lite = LazyMessageLite.newBuilder()
|
||||
.setInner(innerMessage).build();
|
||||
LazyMessageLite lite = LazyMessageLite.newBuilder().setInner(innerMessage).build();
|
||||
assertTrue(lite.getInner().hasExtension(LazyExtension.extension));
|
||||
assertEquals("name", lite.getInner().getExtension(LazyExtension.extension).getName());
|
||||
}
|
||||
|
@ -46,13 +46,13 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class LazyStringArrayListTest extends TestCase {
|
||||
|
||||
private static String STRING_A = "A";
|
||||
private static String STRING_B = "B";
|
||||
private static String STRING_C = "C";
|
||||
private static final String STRING_A = "A";
|
||||
private static final String STRING_B = "B";
|
||||
private static final String STRING_C = "C";
|
||||
|
||||
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
|
||||
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
|
||||
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
|
||||
private static final ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
|
||||
private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
|
||||
private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
|
||||
|
||||
public void testJustStrings() {
|
||||
LazyStringArrayList list = new LazyStringArrayList();
|
||||
@ -175,7 +175,7 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
assertSame(BYTE_STRING_B, list2.getByteString(1));
|
||||
assertSame(BYTE_STRING_C, list2.getByteString(2));
|
||||
}
|
||||
|
||||
|
||||
public void testModificationWithIteration() {
|
||||
LazyStringArrayList list = new LazyStringArrayList();
|
||||
list.addAll(asList(STRING_A, STRING_B, STRING_C));
|
||||
@ -183,12 +183,12 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
assertEquals(3, list.size());
|
||||
assertEquals(STRING_A, list.get(0));
|
||||
assertEquals(STRING_A, iterator.next());
|
||||
|
||||
|
||||
// Does not structurally modify.
|
||||
iterator = list.iterator();
|
||||
list.set(0, STRING_B);
|
||||
iterator.next();
|
||||
|
||||
|
||||
list.remove(0);
|
||||
try {
|
||||
iterator.next();
|
||||
@ -196,7 +196,7 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
} catch (ConcurrentModificationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
iterator = list.iterator();
|
||||
list.add(0, STRING_C);
|
||||
try {
|
||||
@ -206,7 +206,7 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testMakeImmutable() {
|
||||
LazyStringArrayList list = new LazyStringArrayList();
|
||||
list.add(STRING_A);
|
||||
@ -214,52 +214,52 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
list.add(STRING_C);
|
||||
list.makeImmutable();
|
||||
assertGenericListImmutable(list, STRING_A);
|
||||
|
||||
|
||||
// LazyStringArrayList has extra methods not covered in the generic
|
||||
// assertion.
|
||||
|
||||
|
||||
try {
|
||||
list.add(BYTE_STRING_A.toByteArray());
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.add(BYTE_STRING_A);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray()));
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.addAllByteString(asList(BYTE_STRING_A));
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.mergeFrom(new LazyStringArrayList());
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.set(0, BYTE_STRING_A.toByteArray());
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.set(0, BYTE_STRING_A);
|
||||
fail();
|
||||
@ -267,20 +267,20 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testImmutabilityPropagation() {
|
||||
LazyStringArrayList list = new LazyStringArrayList();
|
||||
list.add(STRING_A);
|
||||
list.makeImmutable();
|
||||
|
||||
assertGenericListImmutable(list.asByteStringList(), BYTE_STRING_A);
|
||||
|
||||
|
||||
// Arrays use reference equality so need to retrieve the underlying value
|
||||
// to properly test deep immutability.
|
||||
List<byte[]> byteArrayList = list.asByteArrayList();
|
||||
assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> void assertGenericListImmutable(List<T> list, T value) {
|
||||
try {
|
||||
@ -289,21 +289,21 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.add(0, value);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.addAll(asList(value));
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.addAll(0, asList(value));
|
||||
fail();
|
||||
@ -317,42 +317,42 @@ public class LazyStringArrayListTest extends TestCase {
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.remove(0);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.remove(value);
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.removeAll(asList(value));
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.retainAll(asList());
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.retainAll(asList());
|
||||
fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
list.set(0, value);
|
||||
fail();
|
||||
|
@ -30,44 +30,42 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
|
||||
import protobuf_unittest.UnittestProto;
|
||||
import java.io.IOException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
|
||||
* strings works correctly.
|
||||
* Tests to make sure the lazy conversion of UTF8-encoded byte arrays to strings works correctly.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class LazyStringEndToEndTest extends TestCase {
|
||||
|
||||
private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
|
||||
ByteString.copyFrom(new byte[] {
|
||||
114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
|
||||
0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
|
||||
private static final ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
|
||||
ByteString.copyFrom(
|
||||
new byte[] {
|
||||
114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
|
||||
0, -1, 0, -30, 2, 4, -1, 0, -1, 0,
|
||||
});
|
||||
|
||||
private ByteString encodedTestAllTypes;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
|
||||
.setOptionalString("foo")
|
||||
.addRepeatedString("bar")
|
||||
.addRepeatedString("baz")
|
||||
.build()
|
||||
.toByteString();
|
||||
this.encodedTestAllTypes =
|
||||
UnittestProto.TestAllTypes.newBuilder()
|
||||
.setOptionalString("foo")
|
||||
.addRepeatedString("bar")
|
||||
.addRepeatedString("baz")
|
||||
.build()
|
||||
.toByteString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an invalid UTF8 string will roundtrip through a parse
|
||||
* and serialization.
|
||||
*/
|
||||
/** Tests that an invalid UTF8 string will roundtrip through a parse and serialization. */
|
||||
public void testParseAndSerialize() throws InvalidProtocolBufferException {
|
||||
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
|
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
|
||||
UnittestProto.TestAllTypes tV2 =
|
||||
UnittestProto.TestAllTypes.parseFrom(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
|
||||
ByteString bytes = tV2.toByteString();
|
||||
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
|
||||
|
||||
@ -77,33 +75,31 @@ public class LazyStringEndToEndTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testParseAndWrite() throws IOException {
|
||||
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
|
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
|
||||
UnittestProto.TestAllTypes tV2 =
|
||||
UnittestProto.TestAllTypes.parseFrom(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
|
||||
byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()];
|
||||
CodedOutputStream outputStream = CodedOutputStream.newInstance(sink);
|
||||
tV2.writeTo(outputStream);
|
||||
outputStream.flush();
|
||||
assertEquals(
|
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
|
||||
ByteString.copyFrom(sink));
|
||||
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, ByteString.copyFrom(sink));
|
||||
}
|
||||
|
||||
|
||||
public void testCaching() {
|
||||
String a = "a";
|
||||
String b = "b";
|
||||
String c = "c";
|
||||
UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.newBuilder()
|
||||
.setOptionalString(a)
|
||||
.addRepeatedString(b)
|
||||
.addRepeatedString(c)
|
||||
.build();
|
||||
UnittestProto.TestAllTypes proto =
|
||||
UnittestProto.TestAllTypes.newBuilder()
|
||||
.setOptionalString(a)
|
||||
.addRepeatedString(b)
|
||||
.addRepeatedString(c)
|
||||
.build();
|
||||
|
||||
// String should be the one we passed it.
|
||||
assertSame(a, proto.getOptionalString());
|
||||
assertSame(b, proto.getRepeatedString(0));
|
||||
assertSame(c, proto.getRepeatedString(1));
|
||||
|
||||
|
||||
// Ensure serialization keeps strings cached.
|
||||
proto.toByteString();
|
||||
|
||||
@ -114,8 +110,7 @@ public class LazyStringEndToEndTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
|
||||
UnittestProto.TestAllTypes proto =
|
||||
UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
|
||||
UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
|
||||
ByteString optional = proto.getOptionalStringBytes();
|
||||
assertSame(optional, proto.getOptionalStringBytes());
|
||||
assertSame(optional, proto.toBuilder().getOptionalStringBytes());
|
||||
|
@ -46,9 +46,9 @@ import java.util.NoSuchElementException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}.
|
||||
* This class is designed to be extended for testing extensions of {@code LiteralByteString}
|
||||
* such as {@code BoundedByteString}, see {@link BoundedByteStringTest}.
|
||||
* Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}. This class
|
||||
* is designed to be extended for testing extensions of {@code LiteralByteString} such as {@code
|
||||
* BoundedByteString}, see {@link BoundedByteStringTest}.
|
||||
*
|
||||
* @author carlanton@google.com (Carl Haverl)
|
||||
*/
|
||||
@ -114,7 +114,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSize() {
|
||||
assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
|
||||
assertEquals(
|
||||
classUnderTest + " must have the expected size",
|
||||
referenceBytes.length,
|
||||
stringUnderTest.size());
|
||||
}
|
||||
|
||||
@ -146,10 +148,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
|
||||
try {
|
||||
// Copy one too many bytes
|
||||
stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length,
|
||||
destinationOffset, length);
|
||||
fail("Should have thrown an exception when copying too many bytes of a "
|
||||
+ classUnderTest);
|
||||
stringUnderTest.copyTo(
|
||||
destination, stringUnderTest.size() + 1 - length, destinationOffset, length);
|
||||
fail("Should have thrown an exception when copying too many bytes of a " + classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -157,8 +158,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
try {
|
||||
// Copy with illegal negative sourceOffset
|
||||
stringUnderTest.copyTo(destination, -1, destinationOffset, length);
|
||||
fail("Should have thrown an exception when given a negative sourceOffset in "
|
||||
+ classUnderTest);
|
||||
fail(
|
||||
"Should have thrown an exception when given a negative sourceOffset in "
|
||||
+ classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -166,8 +168,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
try {
|
||||
// Copy with illegal negative destinationOffset
|
||||
stringUnderTest.copyTo(destination, 0, -1, length);
|
||||
fail("Should have thrown an exception when given a negative destinationOffset in "
|
||||
+ classUnderTest);
|
||||
fail(
|
||||
"Should have thrown an exception when given a negative destinationOffset in "
|
||||
+ classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -175,8 +178,7 @@ public class LiteralByteStringTest extends TestCase {
|
||||
try {
|
||||
// Copy with illegal negative size
|
||||
stringUnderTest.copyTo(destination, 0, 0, -1);
|
||||
fail("Should have thrown an exception when given a negative size in "
|
||||
+ classUnderTest);
|
||||
fail("Should have thrown an exception when given a negative size in " + classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -184,8 +186,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
try {
|
||||
// Copy with illegal too-large sourceOffset
|
||||
stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
|
||||
fail("Should have thrown an exception when the destinationOffset is too large in "
|
||||
+ classUnderTest);
|
||||
fail(
|
||||
"Should have thrown an exception when the destinationOffset is too large in "
|
||||
+ classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -193,8 +196,9 @@ public class LiteralByteStringTest extends TestCase {
|
||||
try {
|
||||
// Copy with illegal too-large destinationOffset
|
||||
stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
|
||||
fail("Should have thrown an exception when the destinationOffset is too large in "
|
||||
+ classUnderTest);
|
||||
fail(
|
||||
"Should have thrown an exception when the destinationOffset is too large in "
|
||||
+ classUnderTest);
|
||||
} catch (IndexOutOfBoundsException expected) {
|
||||
// This is success
|
||||
}
|
||||
@ -203,7 +207,8 @@ public class LiteralByteStringTest extends TestCase {
|
||||
public void testCopyTo_ByteBuffer() {
|
||||
ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
|
||||
stringUnderTest.copyTo(myBuffer);
|
||||
assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
|
||||
assertTrue(
|
||||
classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, myBuffer.array()));
|
||||
}
|
||||
|
||||
@ -233,17 +238,15 @@ public class LiteralByteStringTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards {@code n} bytes of data from the input stream. This method
|
||||
* will block until the full amount has been skipped. Does not close the
|
||||
* stream.
|
||||
* Discards {@code n} bytes of data from the input stream. This method will block until the full
|
||||
* amount has been skipped. Does not close the stream.
|
||||
*
|
||||
* <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency.
|
||||
*
|
||||
* @param in the input stream to read from
|
||||
* @param n the number of bytes to skip
|
||||
* @throws EOFException if this stream reaches the end before skipping all
|
||||
* the bytes
|
||||
* @throws IOException if an I/O error occurs, or the stream does not
|
||||
* support skipping
|
||||
* @throws EOFException if this stream reaches the end before skipping all the bytes
|
||||
* @throws IOException if an I/O error occurs, or the stream does not support skipping
|
||||
*/
|
||||
static void skipFully(InputStream in, long n) throws IOException {
|
||||
long toSkip = n;
|
||||
@ -253,8 +256,12 @@ public class LiteralByteStringTest extends TestCase {
|
||||
// Force a blocking read to avoid infinite loop
|
||||
if (in.read() == -1) {
|
||||
long skipped = toSkip - n;
|
||||
throw new EOFException("reached end of stream after skipping "
|
||||
+ skipped + " bytes; " + toSkip + " bytes expected");
|
||||
throw new EOFException(
|
||||
"reached end of stream after skipping "
|
||||
+ skipped
|
||||
+ " bytes; "
|
||||
+ toSkip
|
||||
+ " bytes expected");
|
||||
}
|
||||
n--;
|
||||
} else {
|
||||
@ -269,7 +276,8 @@ public class LiteralByteStringTest extends TestCase {
|
||||
assertTrue(byteBuffer.remaining() == referenceBytes.length);
|
||||
assertTrue(byteBuffer.isReadOnly());
|
||||
byteBuffer.get(roundTripBytes);
|
||||
assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
|
||||
assertTrue(
|
||||
classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, roundTripBytes));
|
||||
}
|
||||
|
||||
@ -285,13 +293,15 @@ public class LiteralByteStringTest extends TestCase {
|
||||
bytesSeen += thisLength;
|
||||
}
|
||||
assertTrue(bytesSeen == referenceBytes.length);
|
||||
assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
|
||||
assertTrue(
|
||||
classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, roundTripBytes));
|
||||
}
|
||||
|
||||
public void testToByteArray() {
|
||||
byte[] roundTripBytes = stringUnderTest.toByteArray();
|
||||
assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
|
||||
assertTrue(
|
||||
classUnderTest + ".toByteArray() must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, roundTripBytes));
|
||||
}
|
||||
|
||||
@ -299,78 +309,85 @@ public class LiteralByteStringTest extends TestCase {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
stringUnderTest.writeTo(bos);
|
||||
byte[] roundTripBytes = bos.toByteArray();
|
||||
assertTrue(classUnderTest + ".writeTo() must give back the same bytes",
|
||||
assertTrue(
|
||||
classUnderTest + ".writeTo() must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, roundTripBytes));
|
||||
}
|
||||
|
||||
public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
|
||||
OutputStream os = new OutputStream() {
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
Arrays.fill(b, off, off + len, (byte) 0);
|
||||
}
|
||||
OutputStream os =
|
||||
new OutputStream() {
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
Arrays.fill(b, off, off + len, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void write(int b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
stringUnderTest.writeTo(os);
|
||||
assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
|
||||
assertTrue(
|
||||
classUnderTest + ".writeTo() must not grant access to underlying array",
|
||||
Arrays.equals(referenceBytes, stringUnderTest.toByteArray()));
|
||||
}
|
||||
|
||||
public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
|
||||
OutputStream os = new OutputStream() {
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
Arrays.fill(b, off, off + len, (byte) 0);
|
||||
}
|
||||
OutputStream os =
|
||||
new OutputStream() {
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
Arrays.fill(b, off, off + len, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void write(int b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
stringUnderTest.writeToInternal(os, 0, stringUnderTest.size());
|
||||
byte[] allZeros = new byte[stringUnderTest.size()];
|
||||
assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
|
||||
assertTrue(
|
||||
classUnderTest + ".writeToInternal() must grant access to underlying array",
|
||||
Arrays.equals(allZeros, stringUnderTest.toByteArray()));
|
||||
}
|
||||
|
||||
public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
|
||||
ByteOutput out = new ByteOutput() {
|
||||
@Override
|
||||
public void write(byte value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
ByteOutput out =
|
||||
new ByteOutput() {
|
||||
@Override
|
||||
public void write(byte value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] value, int offset, int length) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public void write(byte[] value, int offset, int length) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLazy(byte[] value, int offset, int length) throws IOException {
|
||||
Arrays.fill(value, offset, offset + length, (byte) 0);
|
||||
}
|
||||
@Override
|
||||
public void writeLazy(byte[] value, int offset, int length) throws IOException {
|
||||
Arrays.fill(value, offset, offset + length, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public void write(ByteBuffer value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLazy(ByteBuffer value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void writeLazy(ByteBuffer value) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
stringUnderTest.writeTo(out);
|
||||
byte[] allZeros = new byte[stringUnderTest.size()];
|
||||
assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
|
||||
assertTrue(
|
||||
classUnderTest + ".writeToInternal() must grant access to underlying array",
|
||||
Arrays.equals(allZeros, stringUnderTest.toByteArray()));
|
||||
}
|
||||
|
||||
@ -378,21 +395,22 @@ public class LiteralByteStringTest extends TestCase {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ByteString.Output output = ByteString.newOutput();
|
||||
stringUnderTest.writeTo(output);
|
||||
assertEquals("Output Size returns correct result",
|
||||
output.size(), stringUnderTest.size());
|
||||
assertEquals("Output Size returns correct result", output.size(), stringUnderTest.size());
|
||||
output.writeTo(bos);
|
||||
assertTrue("Output.writeTo() must give back the same bytes",
|
||||
assertTrue(
|
||||
"Output.writeTo() must give back the same bytes",
|
||||
Arrays.equals(referenceBytes, bos.toByteArray()));
|
||||
|
||||
// write the output stream to itself! This should cause it to double
|
||||
output.writeTo(output);
|
||||
assertEquals("Writing an output stream to itself is successful",
|
||||
stringUnderTest.concat(stringUnderTest), output.toByteString());
|
||||
assertEquals(
|
||||
"Writing an output stream to itself is successful",
|
||||
stringUnderTest.concat(stringUnderTest),
|
||||
output.toByteString());
|
||||
|
||||
output.reset();
|
||||
assertEquals("Output.reset() resets the output", 0, output.size());
|
||||
assertEquals("Output.reset() resets the output",
|
||||
ByteString.EMPTY, output.toByteString());
|
||||
assertEquals("Output.reset() resets the output", ByteString.EMPTY, output.toByteString());
|
||||
}
|
||||
|
||||
public void testToString() throws UnsupportedEncodingException {
|
||||
@ -410,9 +428,10 @@ public class LiteralByteStringTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testToString_returnsCanonicalEmptyString() {
|
||||
assertSame(classUnderTest + " must be the same string references",
|
||||
assertSame(
|
||||
classUnderTest + " must be the same string references",
|
||||
ByteString.EMPTY.toString(Internal.UTF_8),
|
||||
ByteString.wrap(new byte[]{}).toString(Internal.UTF_8));
|
||||
ByteString.wrap(new byte[] {}).toString(Internal.UTF_8));
|
||||
}
|
||||
|
||||
public void testToString_raisesException() {
|
||||
@ -434,17 +453,23 @@ public class LiteralByteStringTest extends TestCase {
|
||||
public void testEquals() {
|
||||
assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
|
||||
assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
|
||||
assertFalse(classUnderTest + " must not equal the empty string",
|
||||
assertFalse(
|
||||
classUnderTest + " must not equal the empty string",
|
||||
stringUnderTest.equals(ByteString.EMPTY));
|
||||
assertEquals(classUnderTest + " empty strings must be equal",
|
||||
ByteString.wrap(new byte[]{}), stringUnderTest.substring(55, 55));
|
||||
assertEquals(classUnderTest + " must equal another string with the same value",
|
||||
stringUnderTest, ByteString.wrap(referenceBytes));
|
||||
assertEquals(
|
||||
classUnderTest + " empty strings must be equal",
|
||||
ByteString.wrap(new byte[] {}),
|
||||
stringUnderTest.substring(55, 55));
|
||||
assertEquals(
|
||||
classUnderTest + " must equal another string with the same value",
|
||||
stringUnderTest,
|
||||
ByteString.wrap(referenceBytes));
|
||||
|
||||
byte[] mungedBytes = new byte[referenceBytes.length];
|
||||
System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
|
||||
mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
|
||||
assertFalse(classUnderTest + " must not equal every string with the same length",
|
||||
assertFalse(
|
||||
classUnderTest + " must not equal every string with the same length",
|
||||
stringUnderTest.equals(ByteString.wrap(mungedBytes)));
|
||||
}
|
||||
|
||||
@ -454,32 +479,35 @@ public class LiteralByteStringTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testPeekCachedHashCode() {
|
||||
assertEquals(classUnderTest + ".peekCachedHashCode() should return zero at first", 0,
|
||||
assertEquals(
|
||||
classUnderTest + ".peekCachedHashCode() should return zero at first",
|
||||
0,
|
||||
stringUnderTest.peekCachedHashCode());
|
||||
stringUnderTest.hashCode();
|
||||
assertEquals(classUnderTest + ".peekCachedHashCode should return zero at first",
|
||||
expectedHashCode, stringUnderTest.peekCachedHashCode());
|
||||
assertEquals(
|
||||
classUnderTest + ".peekCachedHashCode should return zero at first",
|
||||
expectedHashCode,
|
||||
stringUnderTest.peekCachedHashCode());
|
||||
}
|
||||
|
||||
public void testPartialHash() {
|
||||
// partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
|
||||
// This test would fail if the expected hash were 1. It's not.
|
||||
int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
|
||||
assertEquals(classUnderTest + ".partialHash() must yield expected hashCode",
|
||||
expectedHashCode, hash);
|
||||
assertEquals(
|
||||
classUnderTest + ".partialHash() must yield expected hashCode", expectedHashCode, hash);
|
||||
}
|
||||
|
||||
public void testNewInput() throws IOException {
|
||||
InputStream input = stringUnderTest.newInput();
|
||||
assertEquals("InputStream.available() returns correct value",
|
||||
stringUnderTest.size(), input.available());
|
||||
assertEquals(
|
||||
"InputStream.available() returns correct value", stringUnderTest.size(), input.available());
|
||||
boolean stillEqual = true;
|
||||
for (byte referenceByte : referenceBytes) {
|
||||
int expectedInt = (referenceByte & 0xFF);
|
||||
stillEqual = (expectedInt == input.read());
|
||||
}
|
||||
assertEquals("InputStream.available() returns correct value",
|
||||
0, input.available());
|
||||
assertEquals("InputStream.available() returns correct value", 0, input.available());
|
||||
assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
|
||||
assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
|
||||
}
|
||||
@ -490,43 +518,44 @@ public class LiteralByteStringTest extends TestCase {
|
||||
int nearEndIndex = stringSize * 2 / 3;
|
||||
long skipped1 = input.skip(nearEndIndex);
|
||||
assertEquals("InputStream.skip()", skipped1, nearEndIndex);
|
||||
assertEquals("InputStream.available()",
|
||||
stringSize - skipped1, input.available());
|
||||
assertEquals("InputStream.available()", stringSize - skipped1, input.available());
|
||||
assertTrue("InputStream.mark() is available", input.markSupported());
|
||||
input.mark(0);
|
||||
assertEquals("InputStream.skip(), read()",
|
||||
stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
|
||||
assertEquals("InputStream.available()",
|
||||
stringSize - skipped1 - 1, input.available());
|
||||
assertEquals(
|
||||
"InputStream.skip(), read()", stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
|
||||
assertEquals("InputStream.available()", stringSize - skipped1 - 1, input.available());
|
||||
long skipped2 = input.skip(stringSize);
|
||||
assertEquals("InputStream.skip() incomplete",
|
||||
skipped2, stringSize - skipped1 - 1);
|
||||
assertEquals("InputStream.skip() incomplete", skipped2, stringSize - skipped1 - 1);
|
||||
assertEquals("InputStream.skip(), no more input", 0, input.available());
|
||||
assertEquals("InputStream.skip(), no more input", -1, input.read());
|
||||
input.reset();
|
||||
assertEquals("InputStream.reset() succeded",
|
||||
stringSize - skipped1, input.available());
|
||||
assertEquals("InputStream.reset(), read()",
|
||||
stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
|
||||
assertEquals("InputStream.reset() succeded", stringSize - skipped1, input.available());
|
||||
assertEquals(
|
||||
"InputStream.reset(), read()", stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
|
||||
}
|
||||
|
||||
public void testNewCodedInput() throws IOException {
|
||||
CodedInputStream cis = stringUnderTest.newCodedInput();
|
||||
byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
|
||||
assertTrue(classUnderTest + " must give the same bytes back from the CodedInputStream",
|
||||
assertTrue(
|
||||
classUnderTest + " must give the same bytes back from the CodedInputStream",
|
||||
Arrays.equals(referenceBytes, roundTripBytes));
|
||||
assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we keep things simple when concatenating with empty. See also
|
||||
* {@link ByteStringTest#testConcat_empty()}.
|
||||
* Make sure we keep things simple when concatenating with empty. See also {@link
|
||||
* ByteStringTest#testConcat_empty()}.
|
||||
*/
|
||||
public void testConcat_empty() {
|
||||
assertSame(classUnderTest + " concatenated with empty must give " + classUnderTest,
|
||||
stringUnderTest.concat(ByteString.EMPTY), stringUnderTest);
|
||||
assertSame("empty concatenated with " + classUnderTest + " must give " + classUnderTest,
|
||||
ByteString.EMPTY.concat(stringUnderTest), stringUnderTest);
|
||||
assertSame(
|
||||
classUnderTest + " concatenated with empty must give " + classUnderTest,
|
||||
stringUnderTest.concat(ByteString.EMPTY),
|
||||
stringUnderTest);
|
||||
assertSame(
|
||||
"empty concatenated with " + classUnderTest + " must give " + classUnderTest,
|
||||
ByteString.EMPTY.concat(stringUnderTest),
|
||||
stringUnderTest);
|
||||
}
|
||||
|
||||
public void testJavaSerialization() throws Exception {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user