Merge commit '36bca61764984ff5395653cf8377ec5daa71b709' as 'libs/protobuf'
This commit is contained in:
54
libs/protobuf/java/BUILD.bazel
Normal file
54
libs/protobuf/java/BUILD.bazel
Normal file
@@ -0,0 +1,54 @@
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_filegroup", "pkg_files", "strip_prefix")
|
||||
|
||||
test_suite(
|
||||
name = "tests",
|
||||
tests = [
|
||||
"//java/core:tests",
|
||||
"//java/kotlin:tests",
|
||||
"//java/kotlin-lite:tests",
|
||||
"//java/lite:tests",
|
||||
"//java/util:tests",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "release",
|
||||
srcs = [
|
||||
"//java/core:release", # contains lite.
|
||||
"//java/kotlin:release",
|
||||
"//java/kotlin-lite:release",
|
||||
"//java/util:release",
|
||||
],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Packaging rules
|
||||
################################################################################
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = [
|
||||
"BUILD.bazel",
|
||||
"README.md",
|
||||
"bom/pom.xml",
|
||||
"lite.md",
|
||||
"pom.xml",
|
||||
"protoc/pom.xml",
|
||||
],
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
pkg_filegroup(
|
||||
name = "all_dist_files",
|
||||
srcs = [
|
||||
":dist_files",
|
||||
"//java/core:dist_files",
|
||||
"//java/internal:dist_files",
|
||||
"//java/kotlin:dist_files",
|
||||
"//java/kotlin-lite:dist_files",
|
||||
"//java/lite:dist_files",
|
||||
"//java/util:dist_files",
|
||||
],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
185
libs/protobuf/java/README.md
Normal file
185
libs/protobuf/java/README.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
|
||||
Copyright 2008 Google Inc.
|
||||
|
||||
https://developers.google.com/protocol-buffers/
|
||||
|
||||
## Use Java Protocol Buffers
|
||||
|
||||
To use protobuf in Java, first obtain the protocol compiler (a.k.a., protoc,
|
||||
see instructions in the toplevel [README.md](../README.md)) and use it to
|
||||
generate Java code for your .proto files:
|
||||
|
||||
$ protoc --java_out=${OUTPUT_DIR} path/to/your/proto/file
|
||||
|
||||
Include the generated Java files in your project and add a dependency on the
|
||||
protobuf Java runtime.
|
||||
|
||||
### Maven
|
||||
|
||||
If you are using Maven, use the following:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>3.21.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Make sure the version number of the runtime matches (or is newer than) the
|
||||
version number of the protoc.
|
||||
|
||||
If you want to use features like protobuf JsonFormat, add a dependency on the
|
||||
protobuf-java-util package:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>3.21.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
|
||||
If you are using Gradle, add the following to your `build.gradle` file's dependencies:
|
||||
```
|
||||
implementation 'com.google.protobuf:protobuf-java:3.21.8'
|
||||
```
|
||||
Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using.
|
||||
|
||||
### Use Java Protocol Buffers on Android
|
||||
|
||||
For Android users, it's recommended to use protobuf Java Lite runtime because
|
||||
of its smaller code size. Java Lite runtime also works better with Proguard
|
||||
because it doesn't rely on Java reflection and is optimized to allow as much
|
||||
code stripping as possible. You can following these [instructions to use Java
|
||||
Lite runtime](lite.md).
|
||||
|
||||
### Use Java Protocol Buffers with Bazel
|
||||
|
||||
Bazel has native build rules to work with protobuf. For Java, you can use the
|
||||
`java_proto_library` rule for server and the `java_lite_proto_library` rule
|
||||
for Android. Check out [our build files examples](../examples/BUILD) to learn
|
||||
how to use them.
|
||||
|
||||
## Build from Source
|
||||
|
||||
Most users should follow the instructions above to use protobuf Java runtime.
|
||||
If you are contributing code to protobuf or want to use a protobuf version
|
||||
that hasn't been officially released yet, you can follow the instructions
|
||||
below to build protobuf from source code.
|
||||
|
||||
### Build from Source - With Maven
|
||||
|
||||
1) Install Apache Maven if you don't have it:
|
||||
|
||||
http://maven.apache.org/
|
||||
|
||||
2) Build the C++ code, or obtain a binary distribution of protoc (see
|
||||
the toplevel [README.md](../README.md)). If you install a binary
|
||||
distribution, make sure that it is the same version as this package.
|
||||
If in doubt, run:
|
||||
|
||||
$ protoc --version
|
||||
|
||||
You will need to place the protoc executable in ../src. (If you
|
||||
built it yourself, it should already be there.)
|
||||
|
||||
3) Run the tests:
|
||||
|
||||
$ mvn test
|
||||
|
||||
If some tests fail, this library may not work correctly on your
|
||||
system. Continue at your own risk.
|
||||
|
||||
4) Install the library into your Maven repository:
|
||||
|
||||
$ mvn install
|
||||
|
||||
5) If you do not use Maven to manage your own build, you can build a
|
||||
.jar file to use:
|
||||
|
||||
$ mvn package
|
||||
|
||||
The .jar will be placed in the "target" directory.
|
||||
|
||||
The above instructions will install 2 maven artifacts:
|
||||
|
||||
* protobuf-java: The core Java Protocol Buffers library. Most users only
|
||||
need this artifact.
|
||||
* protobuf-java-util: Utilities to work with protos. It contains JSON support
|
||||
as well as utilities to work with proto3 well-known
|
||||
types.
|
||||
|
||||
### Build from Source - Without Maven
|
||||
|
||||
If you would rather not install Maven to build the library, you may
|
||||
follow these instructions instead. Note that these instructions skip
|
||||
running unit tests and only describes how to install the core protobuf
|
||||
library (without the util package).
|
||||
|
||||
1) Build the C++ code, or obtain a binary distribution of protoc. If
|
||||
you install a binary distribution, make sure that it is the same
|
||||
version as this package. If in doubt, run:
|
||||
|
||||
$ protoc --version
|
||||
|
||||
If you built the C++ code without installing, the compiler binary
|
||||
should be located in ../src.
|
||||
|
||||
2) Invoke protoc to build DescriptorProtos.java:
|
||||
|
||||
$ protoc --java_out=core/src/main/java -I../src \
|
||||
../src/google/protobuf/descriptor.proto
|
||||
|
||||
3) Compile the code in core/src/main/java using whatever means you prefer.
|
||||
|
||||
4) Install the classes wherever you prefer.
|
||||
|
||||
## Compatibility Notice
|
||||
|
||||
* Protobuf minor version releases are backwards-compatible. If your code
|
||||
can build/run against the old version, it's expected to build/run against
|
||||
the new version as well. Both binary compatibility and source compatibility
|
||||
are guaranteed for minor version releases if the user follows the guideline
|
||||
described in this section.
|
||||
|
||||
* Protobuf major version releases may also be backwards-compatible with the
|
||||
last release of the previous major version. See the release notice for more
|
||||
details.
|
||||
|
||||
* APIs marked with the @ExperimentalApi annotation are subject to change. They
|
||||
can be modified in any way, or even removed, at any time. Don't use them if
|
||||
compatibility is needed. If your code is a library itself (i.e. it is used on
|
||||
the CLASSPATH of users outside your own control), you should not use
|
||||
experimental APIs, unless you repackage them (e.g. using ProGuard).
|
||||
|
||||
* Deprecated non-experimental APIs will be removed two years after the release
|
||||
in which they are first deprecated. You must fix your references before this
|
||||
time. If you don't, any manner of breakage could result (you are not
|
||||
guaranteed a compilation error).
|
||||
|
||||
* Protobuf message interfaces/classes are designed to be subclassed by protobuf
|
||||
generated code only. Do not subclass these message interfaces/classes
|
||||
yourself. We may add new methods to the message interfaces/classes which will
|
||||
break your own subclasses.
|
||||
|
||||
* Don't use any method/class that is marked as "used by generated code only".
|
||||
Such methods/classes are subject to change.
|
||||
|
||||
* Protobuf LITE runtime APIs are not stable yet. They are subject to change even
|
||||
in minor version releases.
|
||||
|
||||
## Documentation
|
||||
|
||||
The complete documentation for Protocol Buffers is available via the
|
||||
web at:
|
||||
|
||||
https://developers.google.com/protocol-buffers/
|
||||
|
||||
## Kotlin Protocol Buffers
|
||||
|
||||
Code to support more idiomatic Kotlin protocol buffers has been added to the
|
||||
repository, and Kotlin support will be launched in the next numbered release.
|
||||
110
libs/protobuf/java/bom/pom.xml
Normal file
110
libs/protobuf/java/bom/pom.xml
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-bom</artifactId>
|
||||
<version>3.21.8</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Protocol Buffers [BOM]</name>
|
||||
<description>A compatible set of open source libraries for working with protocol buffers.</description>
|
||||
<url>https://developers.google.com/protocol-buffers/</url>
|
||||
|
||||
<organization>
|
||||
<name>Google LLC</name>
|
||||
<url>https://cloud.google.com</url>
|
||||
</organization>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>haon</id>
|
||||
<name>Hao Nguyen</name>
|
||||
<email>haon@google.com</email>
|
||||
<organization>Google</organization>
|
||||
<organizationUrl>https://cloud.google.com</organizationUrl>
|
||||
<timezone>America/Los_Angeles</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>BSD-3-Clause</name>
|
||||
<url>https://opensource.org/licenses/BSD-3-Clause</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/protocolbuffers/protobuf</url>
|
||||
<connection>scm:git:https://github.com/protocolbuffers/protobuf.git</connection>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- If you see the error message
|
||||
gpg: signing failed: Inappropriate ioctl for device
|
||||
when signing run the command
|
||||
export GPG_TTY=$(tty)
|
||||
and try again. -->
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.6</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
<serverId>sonatype-nexus-staging</serverId>
|
||||
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
493
libs/protobuf/java/core/BUILD.bazel
Normal file
493
libs/protobuf/java/core/BUILD.bazel
Normal file
@@ -0,0 +1,493 @@
|
||||
load("@bazel_skylib//rules:build_test.bzl", "build_test")
|
||||
load("@rules_java//java:defs.bzl", "java_library", "java_lite_proto_library", "java_proto_library")
|
||||
load("@rules_jvm_external//:defs.bzl", "java_export")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain", "proto_library")
|
||||
load("//conformance:defs.bzl", "conformance_test")
|
||||
load("//:protobuf.bzl", "internal_gen_well_known_protos_java")
|
||||
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
|
||||
load("//java/internal:testing.bzl", "junit_tests")
|
||||
|
||||
LITE_SRCS = [
|
||||
# Keep in sync with `//java/lite:pom.xml`.
|
||||
"src/main/java/com/google/protobuf/AbstractMessageLite.java",
|
||||
"src/main/java/com/google/protobuf/AbstractParser.java",
|
||||
"src/main/java/com/google/protobuf/AbstractProtobufList.java",
|
||||
"src/main/java/com/google/protobuf/AllocatedBuffer.java",
|
||||
"src/main/java/com/google/protobuf/Android.java",
|
||||
"src/main/java/com/google/protobuf/ArrayDecoders.java",
|
||||
"src/main/java/com/google/protobuf/BinaryReader.java",
|
||||
"src/main/java/com/google/protobuf/BinaryWriter.java",
|
||||
"src/main/java/com/google/protobuf/BooleanArrayList.java",
|
||||
"src/main/java/com/google/protobuf/BufferAllocator.java",
|
||||
"src/main/java/com/google/protobuf/ByteBufferWriter.java",
|
||||
"src/main/java/com/google/protobuf/ByteOutput.java",
|
||||
"src/main/java/com/google/protobuf/ByteString.java",
|
||||
"src/main/java/com/google/protobuf/CanIgnoreReturnValue.java",
|
||||
"src/main/java/com/google/protobuf/CheckReturnValue.java",
|
||||
"src/main/java/com/google/protobuf/CodedInputStream.java",
|
||||
"src/main/java/com/google/protobuf/CodedInputStreamReader.java",
|
||||
"src/main/java/com/google/protobuf/CodedOutputStream.java",
|
||||
"src/main/java/com/google/protobuf/CodedOutputStreamWriter.java",
|
||||
"src/main/java/com/google/protobuf/CompileTimeConstant.java",
|
||||
"src/main/java/com/google/protobuf/DoubleArrayList.java",
|
||||
"src/main/java/com/google/protobuf/ExperimentalApi.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionLite.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionRegistryFactory.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionRegistryLite.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionSchema.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionSchemaLite.java",
|
||||
"src/main/java/com/google/protobuf/ExtensionSchemas.java",
|
||||
"src/main/java/com/google/protobuf/FieldInfo.java",
|
||||
"src/main/java/com/google/protobuf/FieldSet.java",
|
||||
"src/main/java/com/google/protobuf/FieldType.java",
|
||||
"src/main/java/com/google/protobuf/FloatArrayList.java",
|
||||
"src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java",
|
||||
"src/main/java/com/google/protobuf/GeneratedMessageLite.java",
|
||||
"src/main/java/com/google/protobuf/InlineMe.java",
|
||||
"src/main/java/com/google/protobuf/IntArrayList.java",
|
||||
"src/main/java/com/google/protobuf/Internal.java",
|
||||
"src/main/java/com/google/protobuf/InvalidProtocolBufferException.java",
|
||||
"src/main/java/com/google/protobuf/IterableByteBufferInputStream.java",
|
||||
"src/main/java/com/google/protobuf/JavaType.java",
|
||||
"src/main/java/com/google/protobuf/LazyField.java",
|
||||
"src/main/java/com/google/protobuf/LazyFieldLite.java",
|
||||
"src/main/java/com/google/protobuf/LazyStringArrayList.java",
|
||||
"src/main/java/com/google/protobuf/LazyStringList.java",
|
||||
"src/main/java/com/google/protobuf/ListFieldSchema.java",
|
||||
"src/main/java/com/google/protobuf/LongArrayList.java",
|
||||
"src/main/java/com/google/protobuf/ManifestSchemaFactory.java",
|
||||
"src/main/java/com/google/protobuf/MapEntryLite.java",
|
||||
"src/main/java/com/google/protobuf/MapFieldLite.java",
|
||||
"src/main/java/com/google/protobuf/MapFieldSchema.java",
|
||||
"src/main/java/com/google/protobuf/MapFieldSchemaLite.java",
|
||||
"src/main/java/com/google/protobuf/MapFieldSchemas.java",
|
||||
"src/main/java/com/google/protobuf/MessageInfo.java",
|
||||
"src/main/java/com/google/protobuf/MessageInfoFactory.java",
|
||||
"src/main/java/com/google/protobuf/MessageLite.java",
|
||||
"src/main/java/com/google/protobuf/MessageLiteOrBuilder.java",
|
||||
"src/main/java/com/google/protobuf/MessageLiteToString.java",
|
||||
"src/main/java/com/google/protobuf/MessageSchema.java",
|
||||
"src/main/java/com/google/protobuf/MessageSetSchema.java",
|
||||
"src/main/java/com/google/protobuf/MutabilityOracle.java",
|
||||
"src/main/java/com/google/protobuf/NewInstanceSchema.java",
|
||||
"src/main/java/com/google/protobuf/NewInstanceSchemaLite.java",
|
||||
"src/main/java/com/google/protobuf/NewInstanceSchemas.java",
|
||||
"src/main/java/com/google/protobuf/NioByteString.java",
|
||||
"src/main/java/com/google/protobuf/OneofInfo.java",
|
||||
"src/main/java/com/google/protobuf/Parser.java",
|
||||
"src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java",
|
||||
"src/main/java/com/google/protobuf/ProtoSyntax.java",
|
||||
"src/main/java/com/google/protobuf/Protobuf.java",
|
||||
"src/main/java/com/google/protobuf/ProtobufArrayList.java",
|
||||
"src/main/java/com/google/protobuf/ProtobufLists.java",
|
||||
"src/main/java/com/google/protobuf/ProtocolStringList.java",
|
||||
"src/main/java/com/google/protobuf/RawMessageInfo.java",
|
||||
"src/main/java/com/google/protobuf/Reader.java",
|
||||
"src/main/java/com/google/protobuf/RopeByteString.java",
|
||||
"src/main/java/com/google/protobuf/Schema.java",
|
||||
"src/main/java/com/google/protobuf/SchemaFactory.java",
|
||||
"src/main/java/com/google/protobuf/SchemaUtil.java",
|
||||
"src/main/java/com/google/protobuf/SmallSortedMap.java",
|
||||
"src/main/java/com/google/protobuf/StructuralMessageInfo.java",
|
||||
"src/main/java/com/google/protobuf/TextFormatEscaper.java",
|
||||
"src/main/java/com/google/protobuf/UninitializedMessageException.java",
|
||||
"src/main/java/com/google/protobuf/UnknownFieldSchema.java",
|
||||
"src/main/java/com/google/protobuf/UnknownFieldSetLite.java",
|
||||
"src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java",
|
||||
"src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java",
|
||||
"src/main/java/com/google/protobuf/UnsafeByteOperations.java",
|
||||
"src/main/java/com/google/protobuf/UnsafeUtil.java",
|
||||
"src/main/java/com/google/protobuf/Utf8.java",
|
||||
"src/main/java/com/google/protobuf/WireFormat.java",
|
||||
"src/main/java/com/google/protobuf/Writer.java",
|
||||
]
|
||||
|
||||
internal_gen_well_known_protos_java(
|
||||
name = "gen_well_known_protos_javalite",
|
||||
javalite = True,
|
||||
deps = [
|
||||
"//:any_proto",
|
||||
"//:api_proto",
|
||||
"//:duration_proto",
|
||||
"//:empty_proto",
|
||||
"//:field_mask_proto",
|
||||
"//:source_context_proto",
|
||||
"//:struct_proto",
|
||||
"//:timestamp_proto",
|
||||
"//:type_proto",
|
||||
"//:wrappers_proto",
|
||||
],
|
||||
)
|
||||
|
||||
# Should be used as `//java/lite`.
|
||||
java_library(
|
||||
name = "lite",
|
||||
srcs = LITE_SRCS + [
|
||||
":gen_well_known_protos_javalite",
|
||||
],
|
||||
visibility = [
|
||||
"//java/lite:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
# Bazel users, don't depend on this target, use //java/lite.
|
||||
java_export(
|
||||
name = "lite_mvn",
|
||||
maven_coordinates = "com.google.protobuf:protobuf-javalite:%s" % PROTOBUF_JAVA_VERSION,
|
||||
pom_template = "//java/lite:pom_template.xml",
|
||||
resources = [
|
||||
"//:lite_well_known_protos",
|
||||
],
|
||||
tags = ["manual"],
|
||||
runtime_deps = [":lite"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "lite_runtime_only",
|
||||
srcs = LITE_SRCS,
|
||||
)
|
||||
|
||||
internal_gen_well_known_protos_java(
|
||||
name = "gen_well_known_protos_java",
|
||||
deps = [
|
||||
"//:any_proto",
|
||||
"//:api_proto",
|
||||
"//:compiler_plugin_proto",
|
||||
"//:descriptor_proto",
|
||||
"//:duration_proto",
|
||||
"//:empty_proto",
|
||||
"//:field_mask_proto",
|
||||
"//:source_context_proto",
|
||||
"//:struct_proto",
|
||||
"//:timestamp_proto",
|
||||
"//:type_proto",
|
||||
"//:wrappers_proto",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "core",
|
||||
srcs = glob(
|
||||
[
|
||||
"src/main/java/com/google/protobuf/*.java",
|
||||
],
|
||||
exclude = LITE_SRCS,
|
||||
) + [
|
||||
":gen_well_known_protos_java",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
exports = [
|
||||
":lite_runtime_only",
|
||||
],
|
||||
deps = [
|
||||
":lite_runtime_only",
|
||||
],
|
||||
)
|
||||
|
||||
# Bazel users, don't depend on this target, use :core.
|
||||
java_export(
|
||||
name = "core_mvn",
|
||||
maven_coordinates = "com.google.protobuf:protobuf-java:%s" % PROTOBUF_JAVA_VERSION,
|
||||
pom_template = "pom_template.xml",
|
||||
resources = [
|
||||
"//src/google/protobuf:descriptor_proto_srcs",
|
||||
"//:well_known_type_protos",
|
||||
],
|
||||
tags = ["manual"],
|
||||
runtime_deps = [":core"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "release",
|
||||
srcs = [
|
||||
":core_mvn-docs",
|
||||
":core_mvn-maven-source",
|
||||
":core_mvn-pom",
|
||||
":core_mvn-project",
|
||||
":lite_mvn-docs",
|
||||
":lite_mvn-maven-source",
|
||||
":lite_mvn-pom",
|
||||
":lite_mvn-project",
|
||||
],
|
||||
visibility = ["//java:__pkg__"],
|
||||
)
|
||||
|
||||
proto_lang_toolchain(
|
||||
name = "toolchain",
|
||||
# keep this in sync w/ WELL_KNOWN_PROTO_MAP in //:BUILD
|
||||
blacklisted_protos = [
|
||||
"//:any_proto",
|
||||
"//:api_proto",
|
||||
"//:compiler_plugin_proto",
|
||||
"//:descriptor_proto",
|
||||
"//:duration_proto",
|
||||
"//:empty_proto",
|
||||
"//:field_mask_proto",
|
||||
"//:source_context_proto",
|
||||
"//:struct_proto",
|
||||
"//:timestamp_proto",
|
||||
"//:type_proto",
|
||||
"//:wrappers_proto",
|
||||
],
|
||||
command_line = "--java_out=$(OUT)",
|
||||
runtime = ":core",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "java_test_protos",
|
||||
srcs = glob(["src/test/proto/**/*.proto"]),
|
||||
strip_import_prefix = "src/test/proto",
|
||||
deps = [
|
||||
"//:any_proto",
|
||||
"//:descriptor_proto",
|
||||
"//:lite_test_protos",
|
||||
"//:wrappers_proto",
|
||||
"//src/google/protobuf:generic_test_protos",
|
||||
],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "generic_test_protos_java_proto",
|
||||
visibility = [
|
||||
"//java:__subpackages__",
|
||||
],
|
||||
deps = ["//src/google/protobuf:generic_test_protos"],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "lite_test_protos_java_proto",
|
||||
visibility = [
|
||||
"//java:__subpackages__",
|
||||
],
|
||||
deps = ["//:lite_test_protos"],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "java_test_protos_java_proto",
|
||||
deps = [":java_test_protos"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "test_util",
|
||||
srcs = [
|
||||
"src/test/java/com/google/protobuf/TestUtil.java",
|
||||
"src/test/java/com/google/protobuf/TestUtilLite.java",
|
||||
],
|
||||
visibility = ["//java:__subpackages__"],
|
||||
deps = [
|
||||
":core",
|
||||
":generic_test_protos_java_proto",
|
||||
":java_test_protos_java_proto",
|
||||
":lite_test_protos_java_proto",
|
||||
"@maven//:com_google_guava_guava",
|
||||
"@maven//:junit_junit",
|
||||
],
|
||||
)
|
||||
|
||||
test_suite(
|
||||
name = "tests",
|
||||
tests = [
|
||||
"conformance_test",
|
||||
"core_build_test",
|
||||
"core_tests",
|
||||
"utf8_tests",
|
||||
],
|
||||
)
|
||||
|
||||
build_test(
|
||||
name = "core_build_test",
|
||||
targets = [
|
||||
":core",
|
||||
],
|
||||
)
|
||||
|
||||
conformance_test(
|
||||
name = "conformance_test",
|
||||
failure_list = "//conformance:failure_list_java.txt",
|
||||
testee = "//conformance:conformance_java",
|
||||
text_format_failure_list = "//conformance:text_format_failure_list_java.txt",
|
||||
)
|
||||
|
||||
junit_tests(
|
||||
name = "core_tests",
|
||||
size = "small",
|
||||
srcs = glob(
|
||||
["src/test/java/**/*.java"],
|
||||
exclude = [
|
||||
"src/test/java/com/google/protobuf/DecodeUtf8Test.java",
|
||||
"src/test/java/com/google/protobuf/IsValidUtf8Test.java",
|
||||
"src/test/java/com/google/protobuf/TestUtil.java",
|
||||
"src/test/java/com/google/protobuf/TestUtilLite.java",
|
||||
],
|
||||
),
|
||||
data = ["//src/google/protobuf:testdata"],
|
||||
deps = [
|
||||
":core",
|
||||
":generic_test_protos_java_proto",
|
||||
":java_test_protos_java_proto",
|
||||
":lite_test_protos_java_proto",
|
||||
":test_util",
|
||||
"@maven//:com_google_guava_guava",
|
||||
"@maven//:com_google_truth_truth",
|
||||
"@maven//:junit_junit",
|
||||
"@maven//:org_mockito_mockito_core",
|
||||
],
|
||||
)
|
||||
|
||||
# The UTF-8 validation tests are much slower than the other tests, so they get
|
||||
# their own test target with a longer timeout.
|
||||
junit_tests(
|
||||
name = "utf8_tests",
|
||||
size = "large",
|
||||
srcs = [
|
||||
"src/test/java/com/google/protobuf/DecodeUtf8Test.java",
|
||||
"src/test/java/com/google/protobuf/IsValidUtf8Test.java",
|
||||
"src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java",
|
||||
],
|
||||
deps = [
|
||||
":core",
|
||||
"@maven//:com_google_guava_guava",
|
||||
"@maven//:com_google_truth_truth",
|
||||
"@maven//:junit_junit",
|
||||
],
|
||||
)
|
||||
|
||||
java_lite_proto_library(
|
||||
name = "generic_test_protos_java_proto_lite",
|
||||
visibility = [
|
||||
"//java/kotlin-lite:__pkg__",
|
||||
"//java/lite:__pkg__",
|
||||
],
|
||||
deps = ["//src/google/protobuf:generic_test_protos"],
|
||||
)
|
||||
|
||||
java_lite_proto_library(
|
||||
name = "lite_test_protos_java_proto_lite",
|
||||
visibility = [
|
||||
"//java/kotlin-lite:__pkg__",
|
||||
"//java/lite:__pkg__",
|
||||
],
|
||||
deps = ["//:lite_test_protos"],
|
||||
)
|
||||
|
||||
java_lite_proto_library(
|
||||
name = "java_test_protos_java_proto_lite",
|
||||
visibility = [
|
||||
"//java/lite:__pkg__",
|
||||
],
|
||||
deps = [":java_test_protos"],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "rewrite_javalite_test_util",
|
||||
srcs = [
|
||||
"//java/lite:lite.awk",
|
||||
"src/test/java/com/google/protobuf/TestUtil.java",
|
||||
],
|
||||
outs = ["TestUtil.java"],
|
||||
cmd = "awk -f $(location //java/lite:lite.awk) $(location src/test/java/com/google/protobuf/TestUtil.java) > $@",
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "test_util_lite",
|
||||
srcs = [
|
||||
"src/test/java/com/google/protobuf/TestUtilLite.java",
|
||||
":rewrite_javalite_test_util",
|
||||
],
|
||||
visibility = [
|
||||
"//java/kotlin-lite:__pkg__",
|
||||
"//java/lite:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":generic_test_protos_java_proto_lite",
|
||||
":java_test_protos_java_proto_lite",
|
||||
":lite_runtime_only",
|
||||
":lite_test_protos_java_proto_lite",
|
||||
"@maven//:com_google_guava_guava",
|
||||
"@maven//:junit_junit",
|
||||
],
|
||||
)
|
||||
|
||||
LITE_TEST_EXCLUSIONS = [
|
||||
# Keep in sync with //java/lite:pom.xml id=copy-test-source-files execution.
|
||||
"src/test/java/com/google/protobuf/AbstractMessageTest.java",
|
||||
"src/test/java/com/google/protobuf/AbstractProto2SchemaTest.java",
|
||||
"src/test/java/com/google/protobuf/AnyTest.java",
|
||||
"src/test/java/com/google/protobuf/CodedInputStreamTest.java",
|
||||
"src/test/java/com/google/protobuf/DeprecatedFieldTest.java",
|
||||
"src/test/java/com/google/protobuf/DescriptorsTest.java",
|
||||
"src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java",
|
||||
"src/test/java/com/google/protobuf/DynamicMessageTest.java",
|
||||
"src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java",
|
||||
"src/test/java/com/google/protobuf/FieldPresenceTest.java",
|
||||
"src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java",
|
||||
"src/test/java/com/google/protobuf/GeneratedMessageTest.java",
|
||||
"src/test/java/com/google/protobuf/LazyFieldTest.java",
|
||||
"src/test/java/com/google/protobuf/LazyStringEndToEndTest.java",
|
||||
"src/test/java/com/google/protobuf/MapForProto2Test.java",
|
||||
"src/test/java/com/google/protobuf/MapTest.java",
|
||||
"src/test/java/com/google/protobuf/MessageTest.java",
|
||||
"src/test/java/com/google/protobuf/NestedBuildersTest.java",
|
||||
"src/test/java/com/google/protobuf/PackedFieldTest.java",
|
||||
"src/test/java/com/google/protobuf/ParserTest.java",
|
||||
"src/test/java/com/google/protobuf/ParseExceptionsTest.java",
|
||||
"src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java",
|
||||
"src/test/java/com/google/protobuf/Proto2SchemaTest.java",
|
||||
"src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java",
|
||||
"src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java",
|
||||
"src/test/java/com/google/protobuf/ServiceTest.java",
|
||||
"src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java",
|
||||
"src/test/java/com/google/protobuf/TestBadIdentifiers.java",
|
||||
"src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java",
|
||||
"src/test/java/com/google/protobuf/TextFormatParseLocationTest.java",
|
||||
"src/test/java/com/google/protobuf/TextFormatTest.java",
|
||||
"src/test/java/com/google/protobuf/TestUtil.java",
|
||||
"src/test/java/com/google/protobuf/TestUtilLite.java",
|
||||
"src/test/java/com/google/protobuf/TypeRegistryTest.java",
|
||||
"src/test/java/com/google/protobuf/UnknownEnumValueTest.java",
|
||||
"src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java",
|
||||
"src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java",
|
||||
"src/test/java/com/google/protobuf/UnknownFieldSetTest.java",
|
||||
"src/test/java/com/google/protobuf/WellKnownTypesTest.java",
|
||||
"src/test/java/com/google/protobuf/WireFormatTest.java",
|
||||
]
|
||||
|
||||
junit_tests(
|
||||
name = "lite_tests",
|
||||
size = "large",
|
||||
srcs = glob(
|
||||
["src/test/java/**/*.java"],
|
||||
exclude = LITE_TEST_EXCLUSIONS,
|
||||
),
|
||||
data = ["//src/google/protobuf:testdata"],
|
||||
test_prefix = "Lite",
|
||||
deps = [
|
||||
":generic_test_protos_java_proto_lite",
|
||||
":java_test_protos_java_proto_lite",
|
||||
":lite",
|
||||
":lite_test_protos_java_proto_lite",
|
||||
":test_util_lite",
|
||||
"@maven//:com_google_truth_truth",
|
||||
"@maven//:junit_junit",
|
||||
"@maven//:org_mockito_mockito_core",
|
||||
],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = glob([
|
||||
"src/main/java/com/google/protobuf/*.java",
|
||||
"src/test/java/**/*.java",
|
||||
"src/test/proto/**/*.proto",
|
||||
]) + [
|
||||
"BUILD.bazel",
|
||||
"generate-sources-build.xml",
|
||||
"generate-test-sources-build.xml",
|
||||
"pom.xml",
|
||||
"pom_template.xml",
|
||||
],
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//java:__pkg__"],
|
||||
)
|
||||
20
libs/protobuf/java/core/generate-sources-build.xml
Normal file
20
libs/protobuf/java/core/generate-sources-build.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<project name="generate-sources">
|
||||
<echo message="Running protoc ..."/>
|
||||
<mkdir dir="${generated.sources.dir}"/>
|
||||
<exec executable="${protoc}">
|
||||
<arg value="--java_out=${generated.sources.dir}"/>
|
||||
<arg value="--proto_path=${protobuf.source.dir}"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/duration.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/empty.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/field_mask.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/source_context.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/struct.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/timestamp.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/type.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/wrappers.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/compiler/plugin.proto"/>
|
||||
</exec>
|
||||
</project>
|
||||
62
libs/protobuf/java/core/generate-test-sources-build.xml
Normal file
62
libs/protobuf/java/core/generate-test-sources-build.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<project name="generate-test-sources">
|
||||
<mkdir dir="${generated.testsources.dir}"/>
|
||||
<exec executable="${protoc}">
|
||||
<arg value="--java_out=${generated.testsources.dir}"/>
|
||||
<arg value="--proto_path=${protobuf.source.dir}"/>
|
||||
<arg value="--proto_path=${test.proto.dir}"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/map_lite_unittest.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import_lite.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_mset_wire_format.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_optimize_for.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3_optional.proto"/>
|
||||
<arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/cached_field_size_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/deprecated_file.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/dynamic_message_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/map_lite_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test2.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test3.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/packed_field_test.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/proto2_message.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/proto2_message_lite.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/proto2_unknown_enum_values.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/proto3_message.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/proto3_message_lite.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/test_bad_identifiers.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8_size.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/test_custom_options.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/wrappers_test.proto"/>
|
||||
</exec>
|
||||
<!-- Also generate some Lite protos needed for ExtensionRegistryFactoryTest -->
|
||||
<exec executable="${protoc}">
|
||||
<arg value="--java_out=lite:${generated.testsources.dir}"/>
|
||||
<arg value="--proto_path=${protobuf.source.dir}"/>
|
||||
<arg value="--proto_path=${test.proto.dir}"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
|
||||
<arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension_lite.proto"/>
|
||||
</exec>
|
||||
</project>
|
||||
158
libs/protobuf/java/core/pom.xml
Normal file
158
libs/protobuf/java/core/pom.xml
Normal file
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-parent</artifactId>
|
||||
<version>3.21.8</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>Protocol Buffers [Core]</name>
|
||||
<description>
|
||||
Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
|
||||
efficient yet extensible format.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- Include core protos in the bundle as resources -->
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${protobuf.source.dir}</directory>
|
||||
<includes>
|
||||
<include>google/protobuf/any.proto</include>
|
||||
<include>google/protobuf/api.proto</include>
|
||||
<include>google/protobuf/descriptor.proto</include>
|
||||
<include>google/protobuf/duration.proto</include>
|
||||
<include>google/protobuf/empty.proto</include>
|
||||
<include>google/protobuf/field_mask.proto</include>
|
||||
<include>google/protobuf/source_context.proto</include>
|
||||
<include>google/protobuf/struct.proto</include>
|
||||
<include>google/protobuf/timestamp.proto</include>
|
||||
<include>google/protobuf/type.proto</include>
|
||||
<include>google/protobuf/wrappers.proto</include>
|
||||
<include>google/protobuf/compiler/plugin.proto</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>${protobuf.source.dir}</directory>
|
||||
<includes>
|
||||
<include>google/protobuf/testdata/golden_message_oneof_implemented</include>
|
||||
<include>google/protobuf/testdata/golden_packed_fields_message</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
<plugins>
|
||||
<!-- Use Antrun plugin to generate sources with protoc -->
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<!-- Generate core protos -->
|
||||
<execution>
|
||||
<id>generate-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<ant antfile="generate-sources-build.xml"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
|
||||
<!-- Generate the test protos -->
|
||||
<execution>
|
||||
<id>generate-test-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<ant antfile="generate-test-sources-build.xml"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Add the generated sources to the build -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-generated-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${generated.sources.dir}</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-generated-test-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${generated.testsources.dir}</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- OSGI bundle configuration -->
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Automatic-Module-Name>com.google.protobuf</Automatic-Module-Name> <!-- Java9+ Jigsaw module name -->
|
||||
<Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
|
||||
<Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
|
||||
<Export-Package>com.google.protobuf;version=${project.version}</Export-Package>
|
||||
<Import-Package>sun.misc;resolution:=optional,*</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
18
libs/protobuf/java/core/pom_template.xml
Normal file
18
libs/protobuf/java/core/pom_template.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>{groupId}</groupId>
|
||||
<artifactId>protobuf-parent</artifactId>
|
||||
<version>{version}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>{artifactId}</artifactId>
|
||||
<packaging>{type}</packaging>
|
||||
|
||||
<name>Protocol Buffers [Core]</name>
|
||||
<description>
|
||||
Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
|
||||
efficient yet extensible format.
|
||||
</description>
|
||||
</project>
|
||||
@@ -0,0 +1,605 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import com.google.protobuf.Internal.EnumLite;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
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.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessage
|
||||
// TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
|
||||
extends AbstractMessageLite implements Message {
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return MessageReflection.isInitialized(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <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();
|
||||
}
|
||||
|
||||
/** Create a nested builder. */
|
||||
protected Message.Builder newBuilderForType(BuilderParent parent) {
|
||||
throw new UnsupportedOperationException("Nested builder is not supported for this type.");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> findInitializationErrors() {
|
||||
return MessageReflection.findMissingFields(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitializationErrorString() {
|
||||
return MessageReflection.delimitWithCommas(findInitializationErrors());
|
||||
}
|
||||
|
||||
// TODO(jieluo): Clear it when all subclasses have implemented this method.
|
||||
@Override
|
||||
public boolean hasOneof(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException("hasOneof() is not implemented.");
|
||||
}
|
||||
|
||||
// TODO(jieluo): Clear it when all subclasses have implemented this method.
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException("getOneofFieldDescriptor() is not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return TextFormat.printer().printToString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final CodedOutputStream output) throws IOException {
|
||||
MessageReflection.writeMessageTo(this, getAllFields(), output, false);
|
||||
}
|
||||
|
||||
protected int memoizedSize = -1;
|
||||
|
||||
@Override
|
||||
int getMemoizedSerializedSize() {
|
||||
return memoizedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setMemoizedSerializedSize(int size) {
|
||||
memoizedSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSize;
|
||||
if (size != -1) {
|
||||
return size;
|
||||
}
|
||||
|
||||
memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
|
||||
return memoizedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof Message)) {
|
||||
return false;
|
||||
}
|
||||
final Message otherMessage = (Message) other;
|
||||
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
|
||||
return false;
|
||||
}
|
||||
return compareFields(getAllFields(), otherMessage.getAllFields())
|
||||
&& getUnknownFields().equals(otherMessage.getUnknownFields());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = memoizedHashCode;
|
||||
if (hash == 0) {
|
||||
hash = 41;
|
||||
hash = (19 * hash) + getDescriptorForType().hashCode();
|
||||
hash = hashFields(hash, getAllFields());
|
||||
hash = (29 * hash) + getUnknownFields().hashCode();
|
||||
memoizedHashCode = hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private static ByteString toByteString(Object value) {
|
||||
if (value instanceof byte[]) {
|
||||
return ByteString.copyFrom((byte[]) value);
|
||||
} else {
|
||||
return (ByteString) value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 toByteString(a).equals(toByteString(b));
|
||||
}
|
||||
|
||||
/** 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()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map result = new HashMap<>();
|
||||
Iterator iterator = list.iterator();
|
||||
Message entry = (Message) iterator.next();
|
||||
Descriptors.Descriptor descriptor = entry.getDescriptorForType();
|
||||
Descriptors.FieldDescriptor key = descriptor.findFieldByName("key");
|
||||
Descriptors.FieldDescriptor value = descriptor.findFieldByName("value");
|
||||
Object fieldValue = entry.getField(value);
|
||||
if (fieldValue instanceof EnumValueDescriptor) {
|
||||
fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
|
||||
}
|
||||
result.put(entry.getField(key), fieldValue);
|
||||
while (iterator.hasNext()) {
|
||||
entry = (Message) iterator.next();
|
||||
fieldValue = entry.getField(value);
|
||||
if (fieldValue instanceof EnumValueDescriptor) {
|
||||
fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
|
||||
}
|
||||
result.put(entry.getField(key), fieldValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 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);
|
||||
Map mb = convertMapEntryListToMap((List) b);
|
||||
return MapFieldLite.equals(ma, mb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two sets 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) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
for (FieldDescriptor descriptor : a.keySet()) {
|
||||
if (!b.containsKey(descriptor)) {
|
||||
return false;
|
||||
}
|
||||
Object value1 = a.get(descriptor);
|
||||
Object value2 = b.get(descriptor);
|
||||
if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
|
||||
if (descriptor.isRepeated()) {
|
||||
List<?> list1 = (List) value1;
|
||||
List<?> list2 = (List) value2;
|
||||
if (list1.size() != list2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
if (!compareBytes(list1.get(i), list2.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Compares a singular bytes field.
|
||||
if (!compareBytes(value1, value2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (descriptor.isMapField()) {
|
||||
if (!compareMapField(value1, value2)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Compare non-bytes fields.
|
||||
if (!value1.equals(value2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 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));
|
||||
}
|
||||
|
||||
/** Get a hash code for given fields and values, using the given seed. */
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
|
||||
for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
|
||||
FieldDescriptor field = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
hash = (37 * hash) + field.getNumber();
|
||||
if (field.isMapField()) {
|
||||
hash = (53 * hash) + hashMapField(value);
|
||||
} else if (field.getType() != FieldDescriptor.Type.ENUM) {
|
||||
hash = (53 * hash) + value.hashCode();
|
||||
} else if (field.isRepeated()) {
|
||||
List<? extends EnumLite> list = (List<? extends EnumLite>) value;
|
||||
hash = (53 * hash) + Internal.hashEnumList(list);
|
||||
} else {
|
||||
hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private helper method for AbstractParser to create UninitializedMessageException with
|
||||
* missing field information.
|
||||
*/
|
||||
@Override
|
||||
UninitializedMessageException newUninitializedMessageException() {
|
||||
return Builder.newUninitializedMessageException(this);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* 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<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
|
||||
@Override
|
||||
public BuilderType clone() {
|
||||
throw new UnsupportedOperationException("clone() should be implemented in subclasses.");
|
||||
}
|
||||
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@Override
|
||||
public boolean hasOneof(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException("hasOneof() is not implemented.");
|
||||
}
|
||||
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException("getOneofFieldDescriptor() is not implemented.");
|
||||
}
|
||||
|
||||
/** TODO(jieluo): Clear it when all subclasses have implemented this method. */
|
||||
@Override
|
||||
public BuilderType clearOneof(OneofDescriptor oneof) {
|
||||
throw new UnsupportedOperationException("clearOneof() is not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType clear() {
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
|
||||
clearField(entry.getKey());
|
||||
}
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findInitializationErrors() {
|
||||
return MessageReflection.findMissingFields(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitializationErrorString() {
|
||||
return MessageReflection.delimitWithCommas(findInitializationErrors());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BuilderType internalMergeFrom(AbstractMessageLite other) {
|
||||
return mergeFrom((Message) other);
|
||||
}
|
||||
|
||||
@Override
|
||||
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.");
|
||||
}
|
||||
|
||||
// Note: We don't attempt to verify that other's fields have valid
|
||||
// types. Doing so would be a losing battle. We'd have to verify
|
||||
// all sub-messages as well, and we'd have to make copies of all of
|
||||
// them to insure that they don't change after verification (since
|
||||
// the Message interface itself cannot enforce immutability of
|
||||
// implementations).
|
||||
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry : allFields.entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
if (field.isRepeated()) {
|
||||
for (final Object element : (List) entry.getValue()) {
|
||||
addRepeatedField(field, element);
|
||||
}
|
||||
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
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());
|
||||
}
|
||||
} else {
|
||||
setField(field, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
mergeUnknownFields(other.getUnknownFields());
|
||||
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
|
||||
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
boolean discardUnknown = input.shouldDiscardUnknownFields();
|
||||
final UnknownFieldSet.Builder unknownFields =
|
||||
discardUnknown ? null : getUnknownFieldSetBuilder();
|
||||
MessageReflection.mergeMessageFrom(this, unknownFields, input, extensionRegistry);
|
||||
if (unknownFields != null) {
|
||||
setUnknownFieldSetBuilder(unknownFields);
|
||||
}
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
protected UnknownFieldSet.Builder getUnknownFieldSetBuilder() {
|
||||
return UnknownFieldSet.newBuilder(getUnknownFields());
|
||||
}
|
||||
|
||||
protected void setUnknownFieldSetBuilder(final UnknownFieldSet.Builder builder) {
|
||||
setUnknownFields(builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
|
||||
setUnknownFields(
|
||||
UnknownFieldSet.newBuilder(getUnknownFields()).mergeFrom(unknownFields).build());
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message.Builder getFieldBuilder(final FieldDescriptor field) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getFieldBuilder() called on an unsupported message type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getRepeatedFieldBuilder() called on an unsupported message type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TextFormat.printer().printToString(this);
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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.");
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// The following definitions seem to be required in order to make javac
|
||||
// not produce weird errors like:
|
||||
//
|
||||
// java/com/google/protobuf/DynamicMessage.java:203: types
|
||||
// com.google.protobuf.AbstractMessage.Builder<
|
||||
// com.google.protobuf.DynamicMessage.Builder> and
|
||||
// com.google.protobuf.AbstractMessage.Builder<
|
||||
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
|
||||
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
|
||||
// return types.
|
||||
//
|
||||
// Strangely, these lines are only needed if javac is invoked separately
|
||||
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
|
||||
// invoked on both simultaneously, it works. (Or maybe the important
|
||||
// point is whether or not DynamicMessage.java is compiled together with
|
||||
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
|
||||
// bug.
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final ByteString data, final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
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)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 {
|
||||
return (BuilderType) super.mergeFrom(input, extensionRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
|
||||
* generated code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static int hashLong(long n) {
|
||||
return (int) (n ^ (n >>> 32));
|
||||
}
|
||||
//
|
||||
/**
|
||||
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
|
||||
* generated code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static int hashBoolean(boolean b) {
|
||||
return b ? 1231 : 1237;
|
||||
}
|
||||
//
|
||||
/**
|
||||
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
|
||||
* generated code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static int hashEnum(EnumLite e) {
|
||||
return e.getNumber();
|
||||
}
|
||||
//
|
||||
/**
|
||||
* @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1
|
||||
* generated code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static int hashEnumList(List<? extends EnumLite> list) {
|
||||
int hash = 1;
|
||||
for (EnumLite e : list) {
|
||||
hash = 31 * hash + hashEnum(e);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
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.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessageLite<
|
||||
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());
|
||||
writeTo(out.getCodedOutput());
|
||||
return out.build();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getSerializingExceptionMessage("ByteString"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
try {
|
||||
final byte[] result = new byte[getSerializedSize()];
|
||||
final CodedOutputStream output = CodedOutputStream.newInstance(result);
|
||||
writeTo(output);
|
||||
output.checkNoSpaceLeft();
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getSerializingExceptionMessage("byte array"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final OutputStream output) throws IOException {
|
||||
final int bufferSize = CodedOutputStream.computePreferredBufferSize(getSerializedSize());
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDelimitedTo(final OutputStream output) throws IOException {
|
||||
final int serialized = getSerializedSize();
|
||||
final int bufferSize =
|
||||
CodedOutputStream.computePreferredBufferSize(
|
||||
CodedOutputStream.computeUInt32SizeNoTag(serialized) + serialized);
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
|
||||
codedOutput.writeUInt32NoTag(serialized);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
// We'd like these to be abstract but some folks are extending this class directly. They shouldn't
|
||||
// be doing that and they should feel bad.
|
||||
int getMemoizedSerializedSize() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
void setMemoizedSerializedSize(int size) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
int getSerializedSize(Schema schema) {
|
||||
int memoizedSerializedSize = getMemoizedSerializedSize();
|
||||
if (memoizedSerializedSize == -1) {
|
||||
memoizedSerializedSize = schema.getSerializedSize(this);
|
||||
setMemoizedSerializedSize(memoizedSerializedSize);
|
||||
}
|
||||
return memoizedSerializedSize;
|
||||
}
|
||||
|
||||
/** 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
|
||||
+ " threw an IOException (should never happen).";
|
||||
}
|
||||
|
||||
protected static void checkByteStringIsUtf8(ByteString byteString)
|
||||
throws IllegalArgumentException {
|
||||
if (!byteString.isValidUtf8()) {
|
||||
throw new IllegalArgumentException("Byte string is not UTF-8.");
|
||||
}
|
||||
}
|
||||
|
||||
// For binary compatibility
|
||||
@Deprecated
|
||||
protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
|
||||
Builder.addAll(values, (List) list);
|
||||
}
|
||||
|
||||
protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
|
||||
Builder.addAll(values, list);
|
||||
}
|
||||
|
||||
/** Interface for an enum which signifies which field in a {@code oneof} was specified. */
|
||||
protected interface InternalOneOfEnum {
|
||||
/**
|
||||
* Retrieves the field number of the field which was set in this {@code oneof}, or {@code 0} if
|
||||
* none were.
|
||||
*/
|
||||
int getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>>
|
||||
implements MessageLite.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
@Override
|
||||
public abstract BuilderType clone();
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
|
||||
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
// Re-defined here for return type covariance.
|
||||
@Override
|
||||
public abstract BuilderType mergeFrom(
|
||||
final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final ByteString data, final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
mergeFrom(input, extensionRegistry);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
|
||||
return mergeFrom(data, 0, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data, final int off, final int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return mergeFrom(data, 0, data.length, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data,
|
||||
final int off,
|
||||
final int len,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input, extensionRegistry);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final InputStream input) throws IOException {
|
||||
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
mergeFrom(codedInput);
|
||||
codedInput.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
mergeFrom(codedInput, extensionRegistry);
|
||||
codedInput.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
LimitedInputStream(InputStream in, int limit) {
|
||||
super(in);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return Math.min(super.available(), limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (limit <= 0) {
|
||||
return -1;
|
||||
}
|
||||
final int result = super.read();
|
||||
if (result >= 0) {
|
||||
--limit;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] b, final int off, int len) throws IOException {
|
||||
if (limit <= 0) {
|
||||
return -1;
|
||||
}
|
||||
len = Math.min(len, limit);
|
||||
final int result = super.read(b, off, len);
|
||||
if (result >= 0) {
|
||||
limit -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
// because we take the minimum of an int and a long, result is guaranteed to be
|
||||
// less than or equal to Integer.MAX_INT so this cast is safe
|
||||
int result = (int) super.skip(Math.min(n, limit));
|
||||
if (result >= 0) {
|
||||
// if the superclass adheres to the contract for skip, this condition is always true
|
||||
limit -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(
|
||||
final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
final int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
return false;
|
||||
}
|
||||
final int size = CodedInputStream.readRawVarint32(firstByte, input);
|
||||
final InputStream limitedInput = new LimitedInputStream(input, size);
|
||||
mergeFrom(limitedInput, extensionRegistry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
|
||||
return mergeDelimitedFrom(input, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // isInstance takes care of this
|
||||
public BuilderType mergeFrom(final MessageLite other) {
|
||||
if (!getDefaultInstanceForType().getClass().isInstance(other)) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(MessageLite) can only merge messages of the same type.");
|
||||
}
|
||||
|
||||
return internalMergeFrom((MessageType) other);
|
||||
}
|
||||
|
||||
protected abstract BuilderType internalMergeFrom(MessageType message);
|
||||
|
||||
private String getReadingExceptionMessage(String target) {
|
||||
return "Reading "
|
||||
+ getClass().getName()
|
||||
+ " from a "
|
||||
+ target
|
||||
+ " threw an IOException (should never happen).";
|
||||
}
|
||||
|
||||
// We check nulls as we iterate to avoid iterating over values twice.
|
||||
private static <T> void addAllCheckingNulls(Iterable<T> values, List<? super T> list) {
|
||||
if (list instanceof ArrayList && values instanceof Collection) {
|
||||
((ArrayList<T>) list).ensureCapacity(list.size() + ((Collection<T>) values).size());
|
||||
}
|
||||
int begin = list.size();
|
||||
for (T value : values) {
|
||||
if (value == null) {
|
||||
// encountered a null value so we must undo our modifications prior to throwing
|
||||
String message = "Element at index " + (list.size() - begin) + " is null.";
|
||||
for (int i = list.size() - 1; i >= begin; i--) {
|
||||
list.remove(i);
|
||||
}
|
||||
throw new NullPointerException(message);
|
||||
}
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Construct an UninitializedMessageException reporting missing fields in the given message. */
|
||||
protected static UninitializedMessageException newUninitializedMessageException(
|
||||
MessageLite message) {
|
||||
return new UninitializedMessageException(message);
|
||||
}
|
||||
|
||||
// For binary compatibility.
|
||||
@Deprecated
|
||||
protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
|
||||
addAll(values, (List<T>) list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the {@code values} to the {@code list}. This is a helper method used by generated code.
|
||||
* Users should ignore it.
|
||||
*
|
||||
* @throws NullPointerException if {@code values} or any of the elements of {@code values} is
|
||||
* null.
|
||||
*/
|
||||
protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
|
||||
checkNotNull(values);
|
||||
if (values instanceof LazyStringList) {
|
||||
// For StringOrByteStringLists, check the underlying elements to avoid
|
||||
// forcing conversions of ByteStrings to Strings.
|
||||
// TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
|
||||
// if even possible to hit this condition as all protobuf methods check for null first,
|
||||
// right?
|
||||
List<?> lazyValues = ((LazyStringList) values).getUnderlyingElements();
|
||||
LazyStringList lazyList = (LazyStringList) list;
|
||||
int begin = list.size();
|
||||
for (Object value : lazyValues) {
|
||||
if (value == null) {
|
||||
// encountered a null value so we must undo our modifications prior to throwing
|
||||
String message = "Element at index " + (lazyList.size() - begin) + " is null.";
|
||||
for (int i = lazyList.size() - 1; i >= begin; i--) {
|
||||
lazyList.remove(i);
|
||||
}
|
||||
throw new NullPointerException(message);
|
||||
}
|
||||
if (value instanceof ByteString) {
|
||||
lazyList.add((ByteString) value);
|
||||
} else {
|
||||
lazyList.add((String) value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (values instanceof PrimitiveNonBoxingCollection) {
|
||||
list.addAll((Collection<T>) values);
|
||||
} else {
|
||||
addAllCheckingNulls(values, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
|
||||
import java.io.IOException;
|
||||
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.
|
||||
*
|
||||
* <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) {
|
||||
if (message instanceof AbstractMessageLite) {
|
||||
return ((AbstractMessageLite) message).newUninitializedMessageException();
|
||||
}
|
||||
return new UninitializedMessageException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if message is initialized.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException if it is not initialized.
|
||||
* @return The message to check.
|
||||
*/
|
||||
private MessageType checkMessageInitialized(MessageType message)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (message != null && !message.isInitialized()) {
|
||||
throw newUninitializedMessageException(message)
|
||||
.asInvalidProtocolBufferException()
|
||||
.setUnfinishedMessage(message);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private static final ExtensionRegistryLite EMPTY_REGISTRY =
|
||||
ExtensionRegistryLite.getEmptyRegistry();
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(CodedInputStream input)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(parsePartialFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException {
|
||||
return parseFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
MessageType message;
|
||||
try {
|
||||
CodedInputStream input = data.newCodedInput();
|
||||
message = parsePartialFrom(input, extensionRegistry);
|
||||
try {
|
||||
input.checkLastTagWas(0);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(message);
|
||||
}
|
||||
return message;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
MessageType message;
|
||||
try {
|
||||
CodedInputStream input = CodedInputStream.newInstance(data);
|
||||
message = parsePartialFrom(input, extensionRegistry);
|
||||
try {
|
||||
input.checkLastTagWas(0);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(message);
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return checkMessageInitialized(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
|
||||
MessageType message = parsePartialFrom(input, extensionRegistry);
|
||||
try {
|
||||
input.checkLastTagWas(0);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(message);
|
||||
}
|
||||
return message;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(data, 0, data.length, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(parsePartialFrom(data, off, len, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, off, len, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, 0, data.length, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
MessageType message = parsePartialFrom(codedInput, extensionRegistry);
|
||||
try {
|
||||
codedInput.checkLastTagWas(0);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(message);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException {
|
||||
return parsePartialFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(parsePartialFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException {
|
||||
return parseFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialDelimitedFrom(
|
||||
InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
int size;
|
||||
try {
|
||||
int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
return null;
|
||||
}
|
||||
size = CodedInputStream.readRawVarint32(firstByte, input);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidProtocolBufferException(e);
|
||||
}
|
||||
InputStream limitedInput = new LimitedInputStream(input, size);
|
||||
return parsePartialFrom(limitedInput, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialDelimitedFrom(InputStream input)
|
||||
throws InvalidProtocolBufferException {
|
||||
return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(parsePartialDelimitedFrom(input, extensionRegistry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException {
|
||||
return parseDelimitedFrom(input, EMPTY_REGISTRY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
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.
|
||||
*/
|
||||
abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
|
||||
|
||||
protected static final int DEFAULT_CAPACITY = 10;
|
||||
|
||||
/** Whether or not this list is modifiable. */
|
||||
private boolean isMutable;
|
||||
|
||||
/** Constructs a mutable list by default. */
|
||||
AbstractProtobufList() {
|
||||
isMutable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof List)) {
|
||||
return false;
|
||||
}
|
||||
// Handle lists that do not support RandomAccess as efficiently as possible by using an iterator
|
||||
// based approach in our super class. Otherwise our index based approach will avoid those
|
||||
// allocations.
|
||||
if (!(o instanceof RandomAccess)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
List<?> other = (List<?>) o;
|
||||
final int size = size();
|
||||
if (size != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!get(i).equals(other.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int size = size();
|
||||
int hashCode = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
hashCode = (31 * hashCode) + get(i).hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
ensureIsMutable();
|
||||
return super.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
ensureIsMutable();
|
||||
super.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
ensureIsMutable();
|
||||
return super.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
ensureIsMutable();
|
||||
return super.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
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();
|
||||
int index = indexOf(o);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@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.
|
||||
*/
|
||||
protected void ensureIsMutable() {
|
||||
if (!isMutable) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A buffer that was allocated by a {@link BufferAllocator}. For every buffer, it is guaranteed that
|
||||
* at least one of {@link #hasArray()} or {@link #hasNioBuffer()} will be {@code true}.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
@ExperimentalApi
|
||||
abstract class AllocatedBuffer {
|
||||
/**
|
||||
* Indicates whether this buffer contains a backing {@link ByteBuffer} (i.e. it is safe to call
|
||||
* {@link #nioBuffer()}).
|
||||
*/
|
||||
public abstract boolean hasNioBuffer();
|
||||
|
||||
/**
|
||||
* Indicates whether this buffer contains a backing array (i.e. it is safe to call {@link
|
||||
* #array()}).
|
||||
*/
|
||||
public abstract boolean hasArray();
|
||||
|
||||
/**
|
||||
* Returns the {@link ByteBuffer} that backs this buffer <i>(optional operation)</i>.
|
||||
*
|
||||
* <p>Call {@link #hasNioBuffer()} before invoking this method in order to ensure that this buffer
|
||||
* has a backing {@link ByteBuffer}.
|
||||
*
|
||||
* @return The {@link ByteBuffer} that backs this buffer
|
||||
* @throws UnsupportedOperationException If this buffer is not backed by a {@link ByteBuffer}.
|
||||
*/
|
||||
public abstract ByteBuffer nioBuffer();
|
||||
|
||||
/**
|
||||
* Returns the byte array that backs this buffer <i>(optional operation)</i>.
|
||||
*
|
||||
* <p>Call {@link #hasArray()} before invoking this method in order to ensure that this buffer has
|
||||
* an accessible backing array.
|
||||
*
|
||||
* @return The array that backs this buffer
|
||||
* @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only
|
||||
* @throws UnsupportedOperationException If this buffer is not backed by an accessible array
|
||||
*/
|
||||
public abstract byte[] array();
|
||||
|
||||
/**
|
||||
* Returns the offset within this buffer's backing array of the first element of the buffer
|
||||
* <i>(optional operation)</i>.
|
||||
*
|
||||
* <p>If this buffer is backed by an array then {@link #position()} corresponds to the array index
|
||||
* {@link #position()} {@code +} {@link #arrayOffset()}.
|
||||
*
|
||||
* <p>Invoke the {@link #hasArray hasArray} method before invoking this method in order to ensure
|
||||
* that this buffer has an accessible backing array.
|
||||
*
|
||||
* @return The offset within this buffer's array of the first element of the buffer
|
||||
* @throws java.nio.ReadOnlyBufferException If this buffer is backed by an array but is read-only
|
||||
* @throws UnsupportedOperationException If this buffer is not backed by an accessible array
|
||||
*/
|
||||
public abstract int arrayOffset();
|
||||
|
||||
/**
|
||||
* Returns this buffer's position.
|
||||
*
|
||||
* @return The position of this buffer
|
||||
*/
|
||||
public abstract int position();
|
||||
|
||||
/**
|
||||
* Sets this buffer's position.
|
||||
*
|
||||
* @param position The new position value; must be non-negative and no larger than the current
|
||||
* limit
|
||||
* @return This buffer
|
||||
* @throws IllegalArgumentException If the preconditions on {@code position} do not hold
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public abstract AllocatedBuffer position(int position);
|
||||
|
||||
/**
|
||||
* Returns this buffer's limit.
|
||||
*
|
||||
* @return The limit of this buffer
|
||||
*/
|
||||
public abstract int limit();
|
||||
|
||||
/**
|
||||
* Returns the number of elements between the current {@link #position()} and the {@link #limit()}
|
||||
* .
|
||||
*
|
||||
* @return The number of elements remaining in this buffer
|
||||
*/
|
||||
public abstract int remaining();
|
||||
|
||||
/**
|
||||
* Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer
|
||||
* will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code 0}, {@link
|
||||
* #position()} == {@code 0} and {@link #limit()} equal to the length of {@code bytes}.
|
||||
*/
|
||||
public static AllocatedBuffer wrap(byte[] bytes) {
|
||||
return wrapNoCheck(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AllocatedBuffer} that is backed by the given array. The returned buffer
|
||||
* will have {@link #hasArray} == {@code true}, {@link #arrayOffset()} == {@code offset}, {@link
|
||||
* #position()} == {@code 0} and {@link #limit()} == {@code length}.
|
||||
*/
|
||||
public static AllocatedBuffer wrap(final byte[] bytes, final int offset, final int length) {
|
||||
if (offset < 0 || length < 0 || (offset + length) > bytes.length) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
String.format("bytes.length=%d, offset=%d, length=%d", bytes.length, offset, length));
|
||||
}
|
||||
|
||||
return wrapNoCheck(bytes, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AllocatedBuffer} that is backed by the given {@link ByteBuffer}. The
|
||||
* returned buffer will have {@link #hasNioBuffer} == {@code true}.
|
||||
*/
|
||||
public static AllocatedBuffer wrap(final ByteBuffer buffer) {
|
||||
checkNotNull(buffer, "buffer");
|
||||
|
||||
return new AllocatedBuffer() {
|
||||
|
||||
@Override
|
||||
public boolean hasNioBuffer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return buffer.hasArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return buffer.arrayOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return buffer.position();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AllocatedBuffer position(int position) {
|
||||
buffer.position(position);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
return buffer.limit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return buffer.remaining();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static AllocatedBuffer wrapNoCheck(
|
||||
final byte[] bytes, final int offset, final int length) {
|
||||
return new AllocatedBuffer() {
|
||||
// Relative to offset.
|
||||
private int position;
|
||||
|
||||
@Override
|
||||
public boolean hasNioBuffer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AllocatedBuffer position(int position) {
|
||||
if (position < 0 || position > length) {
|
||||
throw new IllegalArgumentException("Invalid position: " + position);
|
||||
}
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int limit() {
|
||||
// Relative to offset.
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remaining() {
|
||||
return length - position;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
final class Android {
|
||||
private Android() {
|
||||
}
|
||||
|
||||
// Set to true in lite_proguard_android.pgcfg.
|
||||
@SuppressWarnings("ConstantField")
|
||||
private static boolean ASSUME_ANDROID;
|
||||
|
||||
private static final Class<?> MEMORY_CLASS = getClassForName("libcore.io.Memory");
|
||||
|
||||
private static final boolean IS_ROBOLECTRIC =
|
||||
!ASSUME_ANDROID && getClassForName("org.robolectric.Robolectric") != null;
|
||||
|
||||
/** Returns {@code true} if running on an Android device. */
|
||||
static boolean isOnAndroidDevice() {
|
||||
return ASSUME_ANDROID || (MEMORY_CLASS != null && !IS_ROBOLECTRIC);
|
||||
}
|
||||
|
||||
/** Returns the memory class or {@code null} if not on Android device. */
|
||||
static Class<?> getMemoryClass() {
|
||||
return MEMORY_CLASS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Class<T> getClassForName(String name) {
|
||||
try {
|
||||
return (Class<T>) Class.forName(name);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
Message callBlockingMethod(
|
||||
Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype)
|
||||
throws ServiceException;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Blocking equivalent to {@link Service}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
* @author cpovirk@google.com Chris Povirk
|
||||
*/
|
||||
public interface BlockingService {
|
||||
/** 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.
|
||||
*/
|
||||
Message callBlockingMethod(
|
||||
Descriptors.MethodDescriptor method, RpcController controller, Message request)
|
||||
throws ServiceException;
|
||||
|
||||
/** Equivalent to {@link Service#getRequestPrototype}. */
|
||||
Message getRequestPrototype(Descriptors.MethodDescriptor method);
|
||||
|
||||
/** Equivalent to {@link Service#getResponsePrototype}. */
|
||||
Message getResponsePrototype(Descriptors.MethodDescriptor method);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.BooleanList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link BooleanList} on top of a primitive array.
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class BooleanArrayList extends AbstractProtobufList<Boolean>
|
||||
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0);
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
public static BooleanArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/** The backing store for the list. */
|
||||
private boolean[] array;
|
||||
|
||||
/**
|
||||
* The size of the list distinct from the length of the array. That is, it is the number of
|
||||
* elements set in the list.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** 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}.
|
||||
*/
|
||||
private BooleanArrayList(boolean[] other, int size) {
|
||||
array = other;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
ensureIsMutable();
|
||||
if (toIndex < fromIndex) {
|
||||
throw new IndexOutOfBoundsException("toIndex < fromIndex");
|
||||
}
|
||||
|
||||
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof BooleanArrayList)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
BooleanArrayList other = (BooleanArrayList) o;
|
||||
if (size != other.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean[] arr = other.array;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (array[i] != arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
result = (31 * result) + Internal.hashBoolean(array[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new BooleanArrayList(Arrays.copyOf(array, capacity), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(int index) {
|
||||
return getBoolean(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
if (!(element instanceof Boolean)) {
|
||||
return -1;
|
||||
}
|
||||
boolean unboxedElement = (Boolean) element;
|
||||
int numElems = size();
|
||||
for (int i = 0; i < numElems; i++) {
|
||||
if (array[i] == unboxedElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
return indexOf(element) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean set(int index, Boolean element) {
|
||||
return setBoolean(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBoolean(int index, boolean element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
boolean previousValue = array[index];
|
||||
array[index] = element;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Boolean element) {
|
||||
addBoolean(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Boolean element) {
|
||||
addBoolean(index, element);
|
||||
}
|
||||
|
||||
/** Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addBoolean(boolean element) {
|
||||
ensureIsMutable();
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
boolean[] newArray = new boolean[length];
|
||||
|
||||
System.arraycopy(array, 0, newArray, 0, size);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = 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) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
boolean[] newArray = new boolean[length];
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Boolean> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another BooleanArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof BooleanArrayList)) {
|
||||
return super.addAll(collection);
|
||||
}
|
||||
|
||||
BooleanArrayList list = (BooleanArrayList) collection;
|
||||
if (list.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int overflow = Integer.MAX_VALUE - size;
|
||||
if (overflow < list.size) {
|
||||
// We can't actually represent a list this large.
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
int newSize = size + list.size;
|
||||
if (newSize > array.length) {
|
||||
array = Arrays.copyOf(array, newSize);
|
||||
}
|
||||
|
||||
System.arraycopy(list.array, 0, array, size, list.size);
|
||||
size = newSize;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
boolean value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
|
||||
* {@link IndexOutOfBoundsException} if it is not.
|
||||
*
|
||||
* @param index the index to verify is in range
|
||||
*/
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* An object responsible for allocation of buffers. This is an extension point to enable buffer
|
||||
* pooling within an application.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
@ExperimentalApi
|
||||
abstract class BufferAllocator {
|
||||
private static final BufferAllocator UNPOOLED =
|
||||
new BufferAllocator() {
|
||||
@Override
|
||||
public AllocatedBuffer allocateHeapBuffer(int capacity) {
|
||||
return AllocatedBuffer.wrap(new byte[capacity]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AllocatedBuffer allocateDirectBuffer(int capacity) {
|
||||
return AllocatedBuffer.wrap(ByteBuffer.allocateDirect(capacity));
|
||||
}
|
||||
};
|
||||
|
||||
/** Returns an unpooled buffer allocator, which will create a new buffer for each request. */
|
||||
public static BufferAllocator unpooled() {
|
||||
return UNPOOLED;
|
||||
}
|
||||
|
||||
/** Allocates a buffer with the given capacity that is backed by an array on the heap. */
|
||||
public abstract AllocatedBuffer allocateHeapBuffer(int capacity);
|
||||
|
||||
/** Allocates a direct (i.e. non-heap) buffer with the given capacity. */
|
||||
public abstract AllocatedBuffer allocateDirectBuffer(int capacity);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.ref.SoftReference;
|
||||
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. */
|
||||
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.
|
||||
*/
|
||||
// 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.
|
||||
*/
|
||||
// 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. */
|
||||
// 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).
|
||||
*/
|
||||
private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
|
||||
new ThreadLocal<SoftReference<byte[]>>();
|
||||
|
||||
/** 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);
|
||||
|
||||
/**
|
||||
* For testing purposes only. Clears the cached buffer to force a new allocation on the next
|
||||
* invocation.
|
||||
*/
|
||||
static void clearCachedBuffer() {
|
||||
BUFFER.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the remaining content of the buffer to the given stream. The buffer {@code position}
|
||||
* will remain unchanged by this method.
|
||||
*/
|
||||
static void write(ByteBuffer buffer, OutputStream output) throws IOException {
|
||||
final int initialPos = buffer.position();
|
||||
try {
|
||||
if (buffer.hasArray()) {
|
||||
// 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)) {
|
||||
// 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());
|
||||
while (buffer.hasRemaining()) {
|
||||
int length = min(buffer.remaining(), array.length);
|
||||
buffer.get(array, 0, length);
|
||||
output.write(array, 0, length);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Restore the initial position.
|
||||
buffer.position(initialPos);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getOrCreateBuffer(int requestedSize) {
|
||||
requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
|
||||
|
||||
byte[] buffer = getBuffer();
|
||||
// Only allocate if we need to.
|
||||
if (buffer == null || needToReallocate(requestedSize, buffer.length)) {
|
||||
buffer = new byte[requestedSize];
|
||||
|
||||
// Only cache the buffer if it's not too big.
|
||||
if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
|
||||
setBuffer(buffer);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static boolean needToReallocate(int requestedSize, int bufferLength) {
|
||||
// First check against just the requested length to avoid the multiply.
|
||||
return bufferLength < requestedSize
|
||||
&& bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
|
||||
}
|
||||
|
||||
private static byte[] getBuffer() {
|
||||
SoftReference<byte[]> sr = BUFFER.get();
|
||||
return sr == null ? null : sr.get();
|
||||
}
|
||||
|
||||
private static void setBuffer(byte[] value) {
|
||||
BUFFER.set(new SoftReference<byte[]>(value));
|
||||
}
|
||||
|
||||
private static boolean writeToChannel(ByteBuffer buffer, OutputStream output) throws IOException {
|
||||
if (CHANNEL_FIELD_OFFSET >= 0 && FILE_OUTPUT_STREAM_CLASS.isInstance(output)) {
|
||||
// Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
|
||||
WritableByteChannel channel = null;
|
||||
try {
|
||||
channel = (WritableByteChannel) UnsafeUtil.getObject(output, CHANNEL_FIELD_OFFSET);
|
||||
} catch (ClassCastException e) {
|
||||
// Absorb.
|
||||
}
|
||||
if (channel != null) {
|
||||
channel.write(buffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Class<?> safeGetClass(String className) {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getChannelFieldOffset(Class<?> clazz) {
|
||||
try {
|
||||
if (clazz != null && UnsafeUtil.hasUnsafeArrayOperations()) {
|
||||
Field field = clazz.getDeclaredField("channel");
|
||||
return UnsafeUtil.objectFieldOffset(field);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Absorb
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
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>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
|
||||
* maintain a reference to the buffer beyond the scope of the method call (e.g. until the write
|
||||
* operation completes).
|
||||
*/
|
||||
@ExperimentalApi
|
||||
public abstract class ByteOutput {
|
||||
/**
|
||||
* Writes a single byte.
|
||||
*
|
||||
* @param value the byte to be written
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <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
|
||||
* @param offset the offset of the start of the writable range
|
||||
* @param length the number of bytes to write starting from {@code offset}
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
public abstract void write(byte[] value, int offset, int length) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
|
||||
* beyond the scope of this method call (e.g. write later) since it is considered immutable and is
|
||||
* guaranteed not to change 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
|
||||
* @param offset the offset of the start of the writable range
|
||||
* @param length the number of bytes to write starting from {@code offset}
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <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}
|
||||
* @throws IOException thrown if an error occurred while writing
|
||||
*/
|
||||
public abstract void write(ByteBuffer value) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
|
||||
* beyond the scope of this method call (e.g. write later) since it is considered immutable and is
|
||||
* guaranteed not to change 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}
|
||||
* @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
@@ -0,0 +1,49 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that the return value of the annotated method can be safely ignored.
|
||||
*
|
||||
* <p>This is the opposite of {@link CheckReturnValue}. It can be used inside classes or packages
|
||||
* annotated with {@code @CheckReturnValue} to exempt specific methods from the default.
|
||||
*/
|
||||
@Documented
|
||||
@Target(METHOD) // TODO(kak): consider adding CONSTRUCTOR later if necessary
|
||||
@Retention(CLASS)
|
||||
@interface CanIgnoreReturnValue {}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PACKAGE;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that the return value of the annotated method must be used. An error is triggered when
|
||||
* one of these methods is called but the result is not used.
|
||||
*
|
||||
* <p>{@code @CheckReturnValue} may be applied to a class or package to indicate that all methods in
|
||||
* that class (including indirectly; that is, methods of inner classes within the annotated class)
|
||||
* or package must have their return values used. For convenience, we provide an annotation, {@link
|
||||
* CanIgnoreReturnValue}, to exempt specific methods or classes from this behavior.
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD, CONSTRUCTOR, TYPE, PACKAGE})
|
||||
@Retention(RUNTIME)
|
||||
@interface CheckReturnValue {}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,696 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** An adapter between the {@link Writer} interface and {@link CodedOutputStream}. */
|
||||
@CheckReturnValue
|
||||
@ExperimentalApi
|
||||
final class CodedOutputStreamWriter implements Writer {
|
||||
private final CodedOutputStream output;
|
||||
|
||||
public static CodedOutputStreamWriter forCodedOutput(CodedOutputStream output) {
|
||||
if (output.wrapper != null) {
|
||||
return output.wrapper;
|
||||
}
|
||||
return new CodedOutputStreamWriter(output);
|
||||
}
|
||||
|
||||
private CodedOutputStreamWriter(CodedOutputStream output) {
|
||||
this.output = checkNotNull(output, "output");
|
||||
this.output.wrapper = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldOrder fieldOrder() {
|
||||
return FieldOrder.ASCENDING;
|
||||
}
|
||||
|
||||
public int getTotalBytesWritten() {
|
||||
return output.getTotalBytesWritten();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSFixed32(int fieldNumber, int value) throws IOException {
|
||||
output.writeSFixed32(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt64(int fieldNumber, long value) throws IOException {
|
||||
output.writeInt64(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSFixed64(int fieldNumber, long value) throws IOException {
|
||||
output.writeSFixed64(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFloat(int fieldNumber, float value) throws IOException {
|
||||
output.writeFloat(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDouble(int fieldNumber, double value) throws IOException {
|
||||
output.writeDouble(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEnum(int fieldNumber, int value) throws IOException {
|
||||
output.writeEnum(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUInt64(int fieldNumber, long value) throws IOException {
|
||||
output.writeUInt64(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt32(int fieldNumber, int value) throws IOException {
|
||||
output.writeInt32(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFixed64(int fieldNumber, long value) throws IOException {
|
||||
output.writeFixed64(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFixed32(int fieldNumber, int value) throws IOException {
|
||||
output.writeFixed32(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBool(int fieldNumber, boolean value) throws IOException {
|
||||
output.writeBool(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeString(int fieldNumber, String value) throws IOException {
|
||||
output.writeString(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(int fieldNumber, ByteString value) throws IOException {
|
||||
output.writeBytes(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUInt32(int fieldNumber, int value) throws IOException {
|
||||
output.writeUInt32(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSInt32(int fieldNumber, int value) throws IOException {
|
||||
output.writeSInt32(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSInt64(int fieldNumber, long value) throws IOException {
|
||||
output.writeSInt64(fieldNumber, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(int fieldNumber, Object value) throws IOException {
|
||||
output.writeMessage(fieldNumber, (MessageLite) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
|
||||
output.writeMessage(fieldNumber, (MessageLite) value, schema);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void writeGroup(int fieldNumber, Object value) throws IOException {
|
||||
output.writeGroup(fieldNumber, (MessageLite) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
|
||||
output.writeGroup(fieldNumber, (MessageLite) value, schema);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void writeStartGroup(int fieldNumber) throws IOException {
|
||||
output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void writeEndGroup(int fieldNumber) throws IOException {
|
||||
output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeMessageSetItem(int fieldNumber, Object value) throws IOException {
|
||||
if (value instanceof ByteString) {
|
||||
output.writeRawMessageSetExtension(fieldNumber, (ByteString) value);
|
||||
} else {
|
||||
output.writeMessageSetExtension(fieldNumber, (MessageLite) value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt32List(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeInt32SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeInt32NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeInt32(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFixed32List(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeFixed32SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFixed32NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFixed32(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeInt64SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeInt64NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeInt64(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUInt64List(int fieldNumber, List<Long> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeUInt64SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeUInt64NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeUInt64(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFixed64List(int fieldNumber, List<Long> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeFixed64SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFixed64NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFixed64(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFloatList(int fieldNumber, List<Float> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeFloatSizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFloatNoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeFloat(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDoubleList(int fieldNumber, List<Double> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeDoubleSizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeDoubleNoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeDouble(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEnumList(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeEnumSizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeEnumNoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeEnum(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBoolList(int fieldNumber, List<Boolean> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeBoolSizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeBoolNoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeBool(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStringList(int fieldNumber, List<String> value) throws IOException {
|
||||
if (value instanceof LazyStringList) {
|
||||
final LazyStringList lazyList = (LazyStringList) value;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
writeLazyString(fieldNumber, lazyList.getRaw(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeString(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLazyString(int fieldNumber, Object value) throws IOException {
|
||||
if (value instanceof String) {
|
||||
output.writeString(fieldNumber, (String) value);
|
||||
} else {
|
||||
output.writeBytes(fieldNumber, (ByteString) value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytesList(int fieldNumber, List<ByteString> value) throws IOException {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeBytes(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUInt32List(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeUInt32SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeUInt32NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeUInt32(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeSFixed32SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSFixed32NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSFixed32(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSFixed64List(int fieldNumber, List<Long> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeSFixed64SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSFixed64NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSFixed64(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSInt32List(int fieldNumber, List<Integer> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeSInt32SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSInt32NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSInt32(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSInt64List(int fieldNumber, List<Long> value, boolean packed)
|
||||
throws IOException {
|
||||
if (packed) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
// Compute and write the length of the data.
|
||||
int dataSize = 0;
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
dataSize += CodedOutputStream.computeSInt64SizeNoTag(value.get(i));
|
||||
}
|
||||
output.writeUInt32NoTag(dataSize);
|
||||
|
||||
// Write the data itself, without any tags.
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSInt64NoTag(value.get(i));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
output.writeSInt64(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessageList(int fieldNumber, List<?> value) throws IOException {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
writeMessage(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMessageList(int fieldNumber, List<?> value, Schema schema) throws IOException {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
writeMessage(fieldNumber, value.get(i), schema);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void writeGroupList(int fieldNumber, List<?> value) throws IOException {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
writeGroup(fieldNumber, value.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeGroupList(int fieldNumber, List<?> value, Schema schema) throws IOException {
|
||||
for (int i = 0; i < value.size(); ++i) {
|
||||
writeGroup(fieldNumber, value.get(i), schema);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map)
|
||||
throws IOException {
|
||||
if (output.isSerializationDeterministic()) {
|
||||
writeDeterministicMap(fieldNumber, metadata, map);
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(
|
||||
MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue()));
|
||||
MapEntryLite.writeTo(output, metadata, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> void writeDeterministicMap(
|
||||
int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) throws IOException {
|
||||
switch (metadata.keyType) {
|
||||
case BOOL:
|
||||
V value;
|
||||
if ((value = map.get(Boolean.FALSE)) != null) {
|
||||
writeDeterministicBooleanMapEntry(
|
||||
fieldNumber, /* key= */ false, value, (MapEntryLite.Metadata<Boolean, V>) metadata);
|
||||
}
|
||||
if ((value = map.get(Boolean.TRUE)) != null) {
|
||||
writeDeterministicBooleanMapEntry(
|
||||
fieldNumber, /* key= */ true, value, (MapEntryLite.Metadata<Boolean, V>) metadata);
|
||||
}
|
||||
break;
|
||||
case FIXED32:
|
||||
case INT32:
|
||||
case SFIXED32:
|
||||
case SINT32:
|
||||
case UINT32:
|
||||
writeDeterministicIntegerMap(
|
||||
fieldNumber, (MapEntryLite.Metadata<Integer, V>) metadata, (Map<Integer, V>) map);
|
||||
break;
|
||||
case FIXED64:
|
||||
case INT64:
|
||||
case SFIXED64:
|
||||
case SINT64:
|
||||
case UINT64:
|
||||
writeDeterministicLongMap(
|
||||
fieldNumber, (MapEntryLite.Metadata<Long, V>) metadata, (Map<Long, V>) map);
|
||||
break;
|
||||
case STRING:
|
||||
writeDeterministicStringMap(
|
||||
fieldNumber, (MapEntryLite.Metadata<String, V>) metadata, (Map<String, V>) map);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("does not support key type: " + metadata.keyType);
|
||||
}
|
||||
}
|
||||
|
||||
private <V> void writeDeterministicBooleanMapEntry(
|
||||
int fieldNumber, boolean key, V value, MapEntryLite.Metadata<Boolean, V> metadata)
|
||||
throws IOException {
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
|
||||
MapEntryLite.writeTo(output, metadata, key, value);
|
||||
}
|
||||
|
||||
private <V> void writeDeterministicIntegerMap(
|
||||
int fieldNumber, MapEntryLite.Metadata<Integer, V> metadata, Map<Integer, V> map)
|
||||
throws IOException {
|
||||
int[] keys = new int[map.size()];
|
||||
int index = 0;
|
||||
for (int k : map.keySet()) {
|
||||
keys[index++] = k;
|
||||
}
|
||||
Arrays.sort(keys);
|
||||
for (int key : keys) {
|
||||
V value = map.get(key);
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
|
||||
MapEntryLite.writeTo(output, metadata, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private <V> void writeDeterministicLongMap(
|
||||
int fieldNumber, MapEntryLite.Metadata<Long, V> metadata, Map<Long, V> map)
|
||||
throws IOException {
|
||||
long[] keys = new long[map.size()];
|
||||
int index = 0;
|
||||
for (long k : map.keySet()) {
|
||||
keys[index++] = k;
|
||||
}
|
||||
Arrays.sort(keys);
|
||||
for (long key : keys) {
|
||||
V value = map.get(key);
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
|
||||
MapEntryLite.writeTo(output, metadata, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private <V> void writeDeterministicStringMap(
|
||||
int fieldNumber, MapEntryLite.Metadata<String, V> metadata, Map<String, V> map)
|
||||
throws IOException {
|
||||
String[] keys = new String[map.size()];
|
||||
int index = 0;
|
||||
for (String k : map.keySet()) {
|
||||
keys[index++] = k;
|
||||
}
|
||||
Arrays.sort(keys);
|
||||
for (String key : keys) {
|
||||
V value = map.get(key);
|
||||
output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
|
||||
MapEntryLite.writeTo(output, metadata, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation for method parameter and class field declarations, which denotes that corresponding
|
||||
* actual values must be compile-time constant expressions.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(CLASS)
|
||||
@Target({ElementType.PARAMETER, ElementType.FIELD})
|
||||
@interface CompileTimeConstant {}
|
||||
@@ -0,0 +1,798 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.FieldInfo.forField;
|
||||
import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier;
|
||||
import static com.google.protobuf.FieldInfo.forMapField;
|
||||
import static com.google.protobuf.FieldInfo.forOneofMemberField;
|
||||
import static com.google.protobuf.FieldInfo.forPackedField;
|
||||
import static com.google.protobuf.FieldInfo.forPackedFieldWithEnumVerifier;
|
||||
import static com.google.protobuf.FieldInfo.forProto2OptionalField;
|
||||
import static com.google.protobuf.FieldInfo.forProto2RequiredField;
|
||||
import static com.google.protobuf.FieldInfo.forRepeatedMessageField;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor.Type;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/** A factory for message info based on protobuf descriptors for a {@link GeneratedMessageV3}. */
|
||||
@ExperimentalApi
|
||||
final class DescriptorMessageInfoFactory implements MessageInfoFactory {
|
||||
private static final String GET_DEFAULT_INSTANCE_METHOD_NAME = "getDefaultInstance";
|
||||
private static final DescriptorMessageInfoFactory instance = new DescriptorMessageInfoFactory();
|
||||
|
||||
/**
|
||||
* Names that should be avoided (in UpperCamelCase format). Using them causes the compiler to
|
||||
* generate accessors whose names collide with methods defined in base classes.
|
||||
*
|
||||
* <p>Keep this list in sync with kForbiddenWordList in
|
||||
* src/google/protobuf/compiler/java/java_helpers.cc
|
||||
*/
|
||||
private static final Set<String> specialFieldNames =
|
||||
new HashSet<>(
|
||||
Arrays.asList(
|
||||
// java.lang.Object:
|
||||
"Class",
|
||||
// com.google.protobuf.MessageLiteOrBuilder:
|
||||
"DefaultInstanceForType",
|
||||
// com.google.protobuf.MessageLite:
|
||||
"ParserForType",
|
||||
"SerializedSize",
|
||||
// com.google.protobuf.MessageOrBuilder:
|
||||
"AllFields",
|
||||
"DescriptorForType",
|
||||
"InitializationErrorString",
|
||||
"UnknownFields",
|
||||
// obsolete. kept for backwards compatibility of generated code
|
||||
"CachedSize"));
|
||||
|
||||
// Disallow construction - it's a singleton.
|
||||
private DescriptorMessageInfoFactory() {}
|
||||
|
||||
public static DescriptorMessageInfoFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Class<?> messageType) {
|
||||
return GeneratedMessageV3.class.isAssignableFrom(messageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo messageInfoFor(Class<?> messageType) {
|
||||
if (!GeneratedMessageV3.class.isAssignableFrom(messageType)) {
|
||||
throw new IllegalArgumentException("Unsupported message type: " + messageType.getName());
|
||||
}
|
||||
|
||||
return convert(messageType, descriptorForType(messageType));
|
||||
}
|
||||
|
||||
private static Message getDefaultInstance(Class<?> messageType) {
|
||||
try {
|
||||
Method method = messageType.getDeclaredMethod(GET_DEFAULT_INSTANCE_METHOD_NAME);
|
||||
return (Message) method.invoke(null);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to get default instance for message class " + messageType.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Descriptor descriptorForType(Class<?> messageType) {
|
||||
return getDefaultInstance(messageType).getDescriptorForType();
|
||||
}
|
||||
|
||||
private static MessageInfo convert(Class<?> messageType, Descriptor messageDescriptor) {
|
||||
switch (messageDescriptor.getFile().getSyntax()) {
|
||||
case PROTO2:
|
||||
return convertProto2(messageType, messageDescriptor);
|
||||
case PROTO3:
|
||||
return convertProto3(messageType, messageDescriptor);
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported syntax: " + messageDescriptor.getFile().getSyntax());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class to determine whether a message type needs to implement {@code isInitialized()}.
|
||||
*
|
||||
* <p>If a message type doesn't have any required fields or extensions (directly and
|
||||
* transitively), it doesn't need to implement isInitialized() and can always return true there.
|
||||
* It's a bit tricky to determine whether a type has transitive required fields because protobuf
|
||||
* allows cycle references within the same .proto file (e.g., message Foo has a Bar field, and
|
||||
* message Bar has a Foo field). For that we use Tarjan's strongly connected components algorithm
|
||||
* to classify messages into strongly connected groups. Messages in the same group are
|
||||
* transitively including each other, so they should either all have transitive required fields
|
||||
* (or extensions), or none have.
|
||||
*
|
||||
* <p>This class is thread-safe.
|
||||
*/
|
||||
// <p>The code is adapted from the C++ implementation:
|
||||
// https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/java/java_helpers.h
|
||||
static class IsInitializedCheckAnalyzer {
|
||||
|
||||
private final Map<Descriptor, Boolean> resultCache =
|
||||
new ConcurrentHashMap<Descriptor, Boolean>();
|
||||
|
||||
// The following data members are part of Tarjan's SCC algorithm. See:
|
||||
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
private int index = 0;
|
||||
private final Stack<Node> stack = new Stack<Node>();
|
||||
private final Map<Descriptor, Node> nodeCache = new HashMap<Descriptor, Node>();
|
||||
|
||||
public boolean needsIsInitializedCheck(Descriptor descriptor) {
|
||||
Boolean cachedValue = resultCache.get(descriptor);
|
||||
if (cachedValue != null) {
|
||||
return cachedValue;
|
||||
}
|
||||
synchronized (this) {
|
||||
// Double-check the cache because some other thread may have updated it while we
|
||||
// were acquiring the lock.
|
||||
cachedValue = resultCache.get(descriptor);
|
||||
if (cachedValue != null) {
|
||||
return cachedValue;
|
||||
}
|
||||
return dfs(descriptor).component.needsIsInitializedCheck;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Node {
|
||||
final Descriptor descriptor;
|
||||
final int index;
|
||||
int lowLink;
|
||||
StronglyConnectedComponent component; // null if the node is still on stack.
|
||||
|
||||
Node(Descriptor descriptor, int index) {
|
||||
this.descriptor = descriptor;
|
||||
this.index = index;
|
||||
this.lowLink = index;
|
||||
this.component = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StronglyConnectedComponent {
|
||||
final List<Descriptor> messages = new ArrayList<Descriptor>();
|
||||
boolean needsIsInitializedCheck = false;
|
||||
}
|
||||
|
||||
private Node dfs(Descriptor descriptor) {
|
||||
Node result = new Node(descriptor, index++);
|
||||
stack.push(result);
|
||||
nodeCache.put(descriptor, result);
|
||||
|
||||
// Recurse the fields / nodes in graph
|
||||
for (FieldDescriptor field : descriptor.getFields()) {
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
Node child = nodeCache.get(field.getMessageType());
|
||||
if (child == null) {
|
||||
// Unexplored node
|
||||
child = dfs(field.getMessageType());
|
||||
result.lowLink = Math.min(result.lowLink, child.lowLink);
|
||||
} else {
|
||||
if (child.component == null) {
|
||||
// Still in the stack so we found a back edge.
|
||||
result.lowLink = Math.min(result.lowLink, child.lowLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.index == result.lowLink) {
|
||||
// This is the root of a strongly connected component.
|
||||
StronglyConnectedComponent component = new StronglyConnectedComponent();
|
||||
while (true) {
|
||||
Node node = stack.pop();
|
||||
node.component = component;
|
||||
component.messages.add(node.descriptor);
|
||||
if (node == result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
analyze(component);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Determine whether messages in this SCC needs isInitialized check.
|
||||
private void analyze(StronglyConnectedComponent component) {
|
||||
boolean needsIsInitializedCheck = false;
|
||||
loop:
|
||||
for (Descriptor descriptor : component.messages) {
|
||||
if (descriptor.isExtendable()) {
|
||||
needsIsInitializedCheck = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (FieldDescriptor field : descriptor.getFields()) {
|
||||
if (field.isRequired()) {
|
||||
needsIsInitializedCheck = true;
|
||||
break loop;
|
||||
}
|
||||
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
// Since we are analyzing the graph bottom-up, all referenced fields should either be
|
||||
// in this same component or in a different already-analyzed component.
|
||||
Node node = nodeCache.get(field.getMessageType());
|
||||
if (node.component != component) {
|
||||
if (node.component.needsIsInitializedCheck) {
|
||||
needsIsInitializedCheck = true;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component.needsIsInitializedCheck = needsIsInitializedCheck;
|
||||
|
||||
for (Descriptor descriptor : component.messages) {
|
||||
resultCache.put(descriptor, component.needsIsInitializedCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IsInitializedCheckAnalyzer isInitializedCheckAnalyzer =
|
||||
new IsInitializedCheckAnalyzer();
|
||||
|
||||
private static boolean needsIsInitializedCheck(Descriptor descriptor) {
|
||||
return isInitializedCheckAnalyzer.needsIsInitializedCheck(descriptor);
|
||||
}
|
||||
|
||||
private static StructuralMessageInfo convertProto2(
|
||||
Class<?> messageType, Descriptor messageDescriptor) {
|
||||
List<FieldDescriptor> fieldDescriptors = messageDescriptor.getFields();
|
||||
StructuralMessageInfo.Builder builder =
|
||||
StructuralMessageInfo.newBuilder(fieldDescriptors.size());
|
||||
builder.withDefaultInstance(getDefaultInstance(messageType));
|
||||
builder.withSyntax(ProtoSyntax.PROTO2);
|
||||
builder.withMessageSetWireFormat(messageDescriptor.getOptions().getMessageSetWireFormat());
|
||||
|
||||
OneofState oneofState = new OneofState();
|
||||
int bitFieldIndex = 0;
|
||||
int presenceMask = 1;
|
||||
Field bitField = null;
|
||||
|
||||
// Fields in the descriptor are ordered by the index position in which they appear in the
|
||||
// proto file. This is the same order used to determine the presence mask used in the
|
||||
// bitFields. So to determine the appropriate presence mask to be used for a field, we simply
|
||||
// need to shift the presence mask whenever a presence-checked field is encountered.
|
||||
for (int i = 0; i < fieldDescriptors.size(); ++i) {
|
||||
final FieldDescriptor fd = fieldDescriptors.get(i);
|
||||
boolean enforceUtf8 = fd.getFile().getOptions().getJavaStringCheckUtf8();
|
||||
Internal.EnumVerifier enumVerifier = null;
|
||||
if (fd.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) {
|
||||
enumVerifier =
|
||||
new Internal.EnumVerifier() {
|
||||
@Override
|
||||
public boolean isInRange(int number) {
|
||||
return fd.getEnumType().findValueByNumber(number) != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (fd.getContainingOneof() != null) {
|
||||
// Build a oneof member field.
|
||||
builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, enumVerifier));
|
||||
} else {
|
||||
Field field = field(messageType, fd);
|
||||
int number = fd.getNumber();
|
||||
FieldType type = getFieldType(fd);
|
||||
|
||||
if (fd.isMapField()) {
|
||||
// Map field points to an auto-generated message entry type with the definition:
|
||||
// message MapEntry {
|
||||
// K key = 1;
|
||||
// V value = 2;
|
||||
// }
|
||||
final FieldDescriptor valueField = fd.getMessageType().findFieldByNumber(2);
|
||||
if (valueField.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) {
|
||||
enumVerifier =
|
||||
new Internal.EnumVerifier() {
|
||||
@Override
|
||||
public boolean isInRange(int number) {
|
||||
return valueField.getEnumType().findValueByNumber(number) != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
builder.withField(
|
||||
forMapField(
|
||||
field,
|
||||
number,
|
||||
SchemaUtil.getMapDefaultEntry(messageType, fd.getName()),
|
||||
enumVerifier));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd.isRepeated()) {
|
||||
// Repeated fields are not presence-checked.
|
||||
if (enumVerifier != null) {
|
||||
if (fd.isPacked()) {
|
||||
builder.withField(
|
||||
forPackedFieldWithEnumVerifier(
|
||||
field, number, type, enumVerifier, cachedSizeField(messageType, fd)));
|
||||
} else {
|
||||
builder.withField(forFieldWithEnumVerifier(field, number, type, enumVerifier));
|
||||
}
|
||||
} else if (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
builder.withField(
|
||||
forRepeatedMessageField(
|
||||
field, number, type, getTypeForRepeatedMessageField(messageType, fd)));
|
||||
} else {
|
||||
if (fd.isPacked()) {
|
||||
builder.withField(
|
||||
forPackedField(field, number, type, cachedSizeField(messageType, fd)));
|
||||
} else {
|
||||
builder.withField(forField(field, number, type, enforceUtf8));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bitField == null) {
|
||||
// Lazy-create the next bitfield since we know it must exist.
|
||||
bitField = bitField(messageType, bitFieldIndex);
|
||||
}
|
||||
|
||||
// It's a presence-checked field.
|
||||
if (fd.isRequired()) {
|
||||
builder.withField(
|
||||
forProto2RequiredField(
|
||||
field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
|
||||
} else {
|
||||
builder.withField(
|
||||
forProto2OptionalField(
|
||||
field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
|
||||
}
|
||||
}
|
||||
|
||||
// Update the presence mask for the next iteration. If the shift clears out the mask, we will
|
||||
// go to the next bitField.
|
||||
presenceMask <<= 1;
|
||||
if (presenceMask == 0) {
|
||||
bitField = null;
|
||||
presenceMask = 1;
|
||||
bitFieldIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> fieldsToCheckIsInitialized = new ArrayList<Integer>();
|
||||
for (int i = 0; i < fieldDescriptors.size(); ++i) {
|
||||
FieldDescriptor fd = fieldDescriptors.get(i);
|
||||
if (fd.isRequired()
|
||||
|| (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE
|
||||
&& needsIsInitializedCheck(fd.getMessageType()))) {
|
||||
fieldsToCheckIsInitialized.add(fd.getNumber());
|
||||
}
|
||||
}
|
||||
int[] numbers = new int[fieldsToCheckIsInitialized.size()];
|
||||
for (int i = 0; i < fieldsToCheckIsInitialized.size(); i++) {
|
||||
numbers[i] = fieldsToCheckIsInitialized.get(i);
|
||||
}
|
||||
builder.withCheckInitialized(numbers);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static StructuralMessageInfo convertProto3(
|
||||
Class<?> messageType, Descriptor messageDescriptor) {
|
||||
List<FieldDescriptor> fieldDescriptors = messageDescriptor.getFields();
|
||||
StructuralMessageInfo.Builder builder =
|
||||
StructuralMessageInfo.newBuilder(fieldDescriptors.size());
|
||||
builder.withDefaultInstance(getDefaultInstance(messageType));
|
||||
builder.withSyntax(ProtoSyntax.PROTO3);
|
||||
|
||||
OneofState oneofState = new OneofState();
|
||||
boolean enforceUtf8 = true;
|
||||
for (int i = 0; i < fieldDescriptors.size(); ++i) {
|
||||
FieldDescriptor fd = fieldDescriptors.get(i);
|
||||
if (fd.getContainingOneof() != null && !fd.getContainingOneof().isSynthetic()) {
|
||||
// Build a oneof member field. But only if it is a real oneof, not a proto3 optional
|
||||
builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, null));
|
||||
continue;
|
||||
}
|
||||
if (fd.isMapField()) {
|
||||
builder.withField(
|
||||
forMapField(
|
||||
field(messageType, fd),
|
||||
fd.getNumber(),
|
||||
SchemaUtil.getMapDefaultEntry(messageType, fd.getName()),
|
||||
null));
|
||||
continue;
|
||||
}
|
||||
if (fd.isRepeated() && fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
builder.withField(
|
||||
forRepeatedMessageField(
|
||||
field(messageType, fd),
|
||||
fd.getNumber(),
|
||||
getFieldType(fd),
|
||||
getTypeForRepeatedMessageField(messageType, fd)));
|
||||
continue;
|
||||
}
|
||||
if (fd.isPacked()) {
|
||||
builder.withField(
|
||||
forPackedField(
|
||||
field(messageType, fd),
|
||||
fd.getNumber(),
|
||||
getFieldType(fd),
|
||||
cachedSizeField(messageType, fd)));
|
||||
} else {
|
||||
builder.withField(
|
||||
forField(field(messageType, fd), fd.getNumber(), getFieldType(fd), enforceUtf8));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** Builds info for a oneof member field. */
|
||||
private static FieldInfo buildOneofMember(
|
||||
Class<?> messageType,
|
||||
FieldDescriptor fd,
|
||||
OneofState oneofState,
|
||||
boolean enforceUtf8,
|
||||
Internal.EnumVerifier enumVerifier) {
|
||||
OneofInfo oneof = oneofState.getOneof(messageType, fd.getContainingOneof());
|
||||
FieldType type = getFieldType(fd);
|
||||
Class<?> oneofStoredType = getOneofStoredType(messageType, fd, type);
|
||||
return forOneofMemberField(
|
||||
fd.getNumber(), type, oneof, oneofStoredType, enforceUtf8, enumVerifier);
|
||||
}
|
||||
|
||||
private static Class<?> getOneofStoredType(
|
||||
Class<?> messageType, FieldDescriptor fd, FieldType type) {
|
||||
switch (type.getJavaType()) {
|
||||
case BOOLEAN:
|
||||
return Boolean.class;
|
||||
case BYTE_STRING:
|
||||
return ByteString.class;
|
||||
case DOUBLE:
|
||||
return Double.class;
|
||||
case FLOAT:
|
||||
return Float.class;
|
||||
case ENUM:
|
||||
case INT:
|
||||
return Integer.class;
|
||||
case LONG:
|
||||
return Long.class;
|
||||
case STRING:
|
||||
return String.class;
|
||||
case MESSAGE:
|
||||
return getOneofStoredTypeForMessage(messageType, fd);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid type for oneof: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static FieldType getFieldType(FieldDescriptor fd) {
|
||||
switch (fd.getType()) {
|
||||
case BOOL:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.BOOL;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.BOOL_LIST_PACKED : FieldType.BOOL_LIST;
|
||||
case BYTES:
|
||||
return fd.isRepeated() ? FieldType.BYTES_LIST : FieldType.BYTES;
|
||||
case DOUBLE:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.DOUBLE;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.DOUBLE_LIST_PACKED : FieldType.DOUBLE_LIST;
|
||||
case ENUM:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.ENUM;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.ENUM_LIST_PACKED : FieldType.ENUM_LIST;
|
||||
case FIXED32:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.FIXED32;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.FIXED32_LIST_PACKED : FieldType.FIXED32_LIST;
|
||||
case FIXED64:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.FIXED64;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.FIXED64_LIST_PACKED : FieldType.FIXED64_LIST;
|
||||
case FLOAT:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.FLOAT;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.FLOAT_LIST_PACKED : FieldType.FLOAT_LIST;
|
||||
case GROUP:
|
||||
return fd.isRepeated() ? FieldType.GROUP_LIST : FieldType.GROUP;
|
||||
case INT32:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.INT32;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.INT32_LIST_PACKED : FieldType.INT32_LIST;
|
||||
case INT64:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.INT64;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.INT64_LIST_PACKED : FieldType.INT64_LIST;
|
||||
case MESSAGE:
|
||||
if (fd.isMapField()) {
|
||||
return FieldType.MAP;
|
||||
}
|
||||
return fd.isRepeated() ? FieldType.MESSAGE_LIST : FieldType.MESSAGE;
|
||||
case SFIXED32:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.SFIXED32;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.SFIXED32_LIST_PACKED : FieldType.SFIXED32_LIST;
|
||||
case SFIXED64:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.SFIXED64;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.SFIXED64_LIST_PACKED : FieldType.SFIXED64_LIST;
|
||||
case SINT32:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.SINT32;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.SINT32_LIST_PACKED : FieldType.SINT32_LIST;
|
||||
case SINT64:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.SINT64;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.SINT64_LIST_PACKED : FieldType.SINT64_LIST;
|
||||
case STRING:
|
||||
return fd.isRepeated() ? FieldType.STRING_LIST : FieldType.STRING;
|
||||
case UINT32:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.UINT32;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.UINT32_LIST_PACKED : FieldType.UINT32_LIST;
|
||||
case UINT64:
|
||||
if (!fd.isRepeated()) {
|
||||
return FieldType.UINT64;
|
||||
}
|
||||
return fd.isPacked() ? FieldType.UINT64_LIST_PACKED : FieldType.UINT64_LIST;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported field type: " + fd.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private static Field bitField(Class<?> messageType, int index) {
|
||||
return field(messageType, "bitField" + index + "_");
|
||||
}
|
||||
|
||||
private static Field field(Class<?> messageType, FieldDescriptor fd) {
|
||||
return field(messageType, getFieldName(fd));
|
||||
}
|
||||
|
||||
private static Field cachedSizeField(Class<?> messageType, FieldDescriptor fd) {
|
||||
return field(messageType, getCachedSizeFieldName(fd));
|
||||
}
|
||||
|
||||
private static Field field(Class<?> messageType, String fieldName) {
|
||||
try {
|
||||
return messageType.getDeclaredField(fieldName);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to find field " + fieldName + " in message class " + messageType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
static String getFieldName(FieldDescriptor fd) {
|
||||
String name = (fd.getType() == FieldDescriptor.Type.GROUP)
|
||||
? fd.getMessageType().getName()
|
||||
: fd.getName();
|
||||
|
||||
// convert to UpperCamelCase for comparison to the specialFieldNames
|
||||
// (which are in UpperCamelCase)
|
||||
String upperCamelCaseName = snakeCaseToUpperCamelCase(name);
|
||||
|
||||
// Append underscores to match the behavior of the protoc java compiler
|
||||
final String suffix;
|
||||
if (specialFieldNames.contains(upperCamelCaseName)) {
|
||||
// For proto field names that match the specialFieldNames,
|
||||
// the protoc java compiler appends "__" to the java field name
|
||||
// to prevent the field's accessor method names from clashing with other methods.
|
||||
// For example:
|
||||
// proto field name = "class"
|
||||
// java field name = "class__"
|
||||
// accessor method name = "getClass_()" (so that it does not clash with
|
||||
// Object.getClass())
|
||||
suffix = "__";
|
||||
} else {
|
||||
// For other proto field names,
|
||||
// the protoc java compiler appends "_" to the java field name
|
||||
// to prevent field names from clashing with java keywords.
|
||||
// For example:
|
||||
// proto field name = "int"
|
||||
// java field name = "int_" (so that it does not clash with int keyword)
|
||||
// accessor method name = "getInt()"
|
||||
suffix = "_";
|
||||
}
|
||||
return snakeCaseToLowerCamelCase(name) + suffix;
|
||||
}
|
||||
|
||||
private static String getCachedSizeFieldName(FieldDescriptor fd) {
|
||||
return snakeCaseToLowerCamelCase(fd.getName()) + "MemoizedSerializedSize";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a snake case string into lower camel case.
|
||||
*
|
||||
* <p>Some examples:
|
||||
*
|
||||
* <pre>
|
||||
* snakeCaseToLowerCamelCase("foo_bar") => "fooBar"
|
||||
* snakeCaseToLowerCamelCase("foo") => "foo"
|
||||
* </pre>
|
||||
*
|
||||
* @param snakeCase the string in snake case to convert
|
||||
* @return the string converted to camel case, with a lowercase first character
|
||||
*/
|
||||
private static String snakeCaseToLowerCamelCase(String snakeCase) {
|
||||
return snakeCaseToCamelCase(snakeCase, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a snake case string into upper camel case.
|
||||
*
|
||||
* <p>Some examples:
|
||||
*
|
||||
* <pre>
|
||||
* snakeCaseToUpperCamelCase("foo_bar") => "FooBar"
|
||||
* snakeCaseToUpperCamelCase("foo") => "Foo"
|
||||
* </pre>
|
||||
*
|
||||
* @param snakeCase the string in snake case to convert
|
||||
* @return the string converted to camel case, with an uppercase first character
|
||||
*/
|
||||
private static String snakeCaseToUpperCamelCase(String snakeCase) {
|
||||
return snakeCaseToCamelCase(snakeCase, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a snake case string into camel case.
|
||||
*
|
||||
* <p>For better readability, prefer calling either {@link #snakeCaseToLowerCamelCase(String)} or
|
||||
* {@link #snakeCaseToUpperCamelCase(String)}.
|
||||
*
|
||||
* <p>Some examples:
|
||||
*
|
||||
* <pre>
|
||||
* snakeCaseToCamelCase("foo_bar", false) => "fooBar"
|
||||
* snakeCaseToCamelCase("foo_bar", true) => "FooBar"
|
||||
* snakeCaseToCamelCase("foo", false) => "foo"
|
||||
* snakeCaseToCamelCase("foo", true) => "Foo"
|
||||
* snakeCaseToCamelCase("Foo", false) => "foo"
|
||||
* snakeCaseToCamelCase("fooBar", false) => "fooBar"
|
||||
* </pre>
|
||||
*
|
||||
* <p>This implementation of this method must exactly match the corresponding function in the
|
||||
* protocol compiler. Specifically, the {@code UnderscoresToCamelCase} function in {@code
|
||||
* src/google/protobuf/compiler/java/java_helpers.cc}.
|
||||
*
|
||||
* @param snakeCase the string in snake case to convert
|
||||
* @param capFirst true if the first letter of the returned string should be uppercase. false if
|
||||
* the first letter of the returned string should be lowercase.
|
||||
* @return the string converted to camel case, with an uppercase or lowercase first character
|
||||
* depending on if {@code capFirst} is true or false, respectively
|
||||
*/
|
||||
private static String snakeCaseToCamelCase(String snakeCase, boolean capFirst) {
|
||||
StringBuilder sb = new StringBuilder(snakeCase.length() + 1);
|
||||
boolean capNext = capFirst;
|
||||
for (int ctr = 0; ctr < snakeCase.length(); ctr++) {
|
||||
char next = snakeCase.charAt(ctr);
|
||||
if (next == '_') {
|
||||
capNext = true;
|
||||
} else if (Character.isDigit(next)) {
|
||||
sb.append(next);
|
||||
capNext = true;
|
||||
} else if (capNext) {
|
||||
sb.append(Character.toUpperCase(next));
|
||||
capNext = false;
|
||||
} else if (ctr == 0) {
|
||||
sb.append(Character.toLowerCase(next));
|
||||
} else {
|
||||
sb.append(next);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the message to identify the stored type for a message field that is part of a oneof.
|
||||
*/
|
||||
private static Class<?> getOneofStoredTypeForMessage(Class<?> messageType, FieldDescriptor fd) {
|
||||
try {
|
||||
String name = fd.getType() == Type.GROUP ? fd.getMessageType().getName() : fd.getName();
|
||||
Method getter = messageType.getDeclaredMethod(getterForField(name));
|
||||
return getter.getReturnType();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Inspects the message to identify the message type of a repeated message field. */
|
||||
private static Class<?> getTypeForRepeatedMessageField(Class<?> messageType, FieldDescriptor fd) {
|
||||
try {
|
||||
String name = fd.getType() == Type.GROUP ? fd.getMessageType().getName() : fd.getName();
|
||||
Method getter = messageType.getDeclaredMethod(getterForField(name), int.class);
|
||||
return getter.getReturnType();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs the name of the get method for the given field in the proto. */
|
||||
private static String getterForField(String snakeCase) {
|
||||
String camelCase = snakeCaseToLowerCamelCase(snakeCase);
|
||||
StringBuilder builder = new StringBuilder("get");
|
||||
// Capitalize the first character in the field name.
|
||||
builder.append(Character.toUpperCase(camelCase.charAt(0)));
|
||||
builder.append(camelCase.substring(1, camelCase.length()));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static final class OneofState {
|
||||
private OneofInfo[] oneofs = new OneofInfo[2];
|
||||
|
||||
OneofInfo getOneof(Class<?> messageType, OneofDescriptor desc) {
|
||||
int index = desc.getIndex();
|
||||
if (index >= oneofs.length) {
|
||||
// Grow the array.
|
||||
oneofs = Arrays.copyOf(oneofs, index * 2);
|
||||
}
|
||||
OneofInfo info = oneofs[index];
|
||||
if (info == null) {
|
||||
info = newInfo(messageType, desc);
|
||||
oneofs[index] = info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private static OneofInfo newInfo(Class<?> messageType, OneofDescriptor desc) {
|
||||
String camelCase = snakeCaseToLowerCamelCase(desc.getName());
|
||||
String valueFieldName = camelCase + "_";
|
||||
String caseFieldName = camelCase + "Case_";
|
||||
|
||||
return new OneofInfo(
|
||||
desc.getIndex(), field(messageType, caseFieldName), field(messageType, valueFieldName));
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** Parsers to discard unknown fields during parsing. */
|
||||
public final class DiscardUnknownFieldsParser {
|
||||
|
||||
/**
|
||||
* Wraps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
|
||||
* 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);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Like all other implementations of {@code Parser}, this parser is stateless and thread-safe.
|
||||
*
|
||||
* @param parser The delegated parser that parses messages.
|
||||
* @return a {@link Parser} that will discard unknown fields during parsing.
|
||||
*/
|
||||
public static final <T extends Message> Parser<T> wrap(final Parser<T> parser) {
|
||||
return new AbstractParser<T>() {
|
||||
@Override
|
||||
public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
input.discardUnknownFields();
|
||||
return parser.parsePartialFrom(input, extensionRegistry);
|
||||
} finally {
|
||||
input.unsetDiscardUnknownFields();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private DiscardUnknownFieldsParser() {}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.DoubleList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link DoubleList} on top of a primitive array.
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class DoubleArrayList extends AbstractProtobufList<Double>
|
||||
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(new double[0], 0);
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
public static DoubleArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/** The backing store for the list. */
|
||||
private double[] array;
|
||||
|
||||
/**
|
||||
* The size of the list distinct from the length of the array. That is, it is the number of
|
||||
* elements set in the list.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** 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}.
|
||||
*/
|
||||
private DoubleArrayList(double[] other, int size) {
|
||||
array = other;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
ensureIsMutable();
|
||||
if (toIndex < fromIndex) {
|
||||
throw new IndexOutOfBoundsException("toIndex < fromIndex");
|
||||
}
|
||||
|
||||
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof DoubleArrayList)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
DoubleArrayList other = (DoubleArrayList) o;
|
||||
if (size != other.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final double[] arr = other.array;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (Double.doubleToLongBits(array[i]) != Double.doubleToLongBits(arr[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
long bits = Double.doubleToLongBits(array[i]);
|
||||
result = (31 * result) + Internal.hashLong(bits);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double get(int index) {
|
||||
return getDouble(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
if (!(element instanceof Double)) {
|
||||
return -1;
|
||||
}
|
||||
double unboxedElement = (Double) element;
|
||||
int numElems = size();
|
||||
for (int i = 0; i < numElems; i++) {
|
||||
if (array[i] == unboxedElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
return indexOf(element) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double set(int index, Double element) {
|
||||
return setDouble(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double setDouble(int index, double element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
double previousValue = array[index];
|
||||
array[index] = element;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Double element) {
|
||||
addDouble(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Double element) {
|
||||
addDouble(index, element);
|
||||
}
|
||||
|
||||
/** Like {@link #add(Double)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addDouble(double element) {
|
||||
ensureIsMutable();
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
double[] newArray = new double[length];
|
||||
|
||||
System.arraycopy(array, 0, newArray, 0, size);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = 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) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
double[] newArray = new double[length];
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Double> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another DoubleArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof DoubleArrayList)) {
|
||||
return super.addAll(collection);
|
||||
}
|
||||
|
||||
DoubleArrayList list = (DoubleArrayList) collection;
|
||||
if (list.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int overflow = Integer.MAX_VALUE - size;
|
||||
if (overflow < list.size) {
|
||||
// We can't actually represent a list this large.
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
int newSize = size + list.size;
|
||||
if (newSize > array.length) {
|
||||
array = Arrays.copyOf(array, newSize);
|
||||
}
|
||||
|
||||
System.arraycopy(list.array, 0, array, size, list.size);
|
||||
size = newSize;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
double value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
|
||||
* {@link IndexOutOfBoundsException} if it is not.
|
||||
*
|
||||
* @param index the index to verify is in range
|
||||
*/
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,738 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Message} that can represent arbitrary types, given a {@link
|
||||
* Descriptors.Descriptor}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class DynamicMessage extends AbstractMessage {
|
||||
private final Descriptor type;
|
||||
private final FieldSet<FieldDescriptor> fields;
|
||||
private final FieldDescriptor[] oneofCases;
|
||||
private final UnknownFieldSet unknownFields;
|
||||
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.
|
||||
*
|
||||
* <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) {
|
||||
this.type = type;
|
||||
this.fields = fields;
|
||||
this.oneofCases = oneofCases;
|
||||
this.unknownFields = unknownFields;
|
||||
}
|
||||
|
||||
/** 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());
|
||||
}
|
||||
|
||||
|
||||
/** Parse a message of the given type from the given input stream. */
|
||||
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)
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Construct a {@link Message.Builder} for the given type. */
|
||||
public static Builder newBuilder(Descriptor type) {
|
||||
return new Builder(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Implementation of Message interface.
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage getDefaultInstanceForType() {
|
||||
return getDefaultInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
return fields.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOneof(OneofDescriptor oneof) {
|
||||
verifyOneofContainingType(oneof);
|
||||
FieldDescriptor field = oneofCases[oneof.getIndex()];
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
verifyOneofContainingType(oneof);
|
||||
return oneofCases[oneof.getIndex()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
Object result = fields.getField(field);
|
||||
if (result == null) {
|
||||
if (field.isRepeated()) {
|
||||
result = Collections.emptyList();
|
||||
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
result = getDefaultInstance(field.getMessageType());
|
||||
} else {
|
||||
result = field.getDefaultValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
static boolean isInitialized(Descriptor type, FieldSet<FieldDescriptor> fields) {
|
||||
// Check that all required fields are present.
|
||||
for (final FieldDescriptor field : type.getFields()) {
|
||||
if (field.isRequired()) {
|
||||
if (!fields.hasField(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that embedded messages are initialized.
|
||||
return fields.isInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return isInitialized(type, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(CodedOutputStream output) throws IOException {
|
||||
if (type.getOptions().getMessageSetWireFormat()) {
|
||||
fields.writeMessageSetTo(output);
|
||||
unknownFields.writeAsMessageSetTo(output);
|
||||
} else {
|
||||
fields.writeTo(output);
|
||||
unknownFields.writeTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSize;
|
||||
if (size != -1) return size;
|
||||
|
||||
if (type.getOptions().getMessageSetWireFormat()) {
|
||||
size = fields.getMessageSetSerializedSize();
|
||||
size += unknownFields.getSerializedSizeAsMessageSet();
|
||||
} else {
|
||||
size = fields.getSerializedSize();
|
||||
size += unknownFields.getSerializedSize();
|
||||
}
|
||||
|
||||
memoizedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForType() {
|
||||
return new Builder(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return newBuilderForType().mergeFrom(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser<DynamicMessage> getParserForType() {
|
||||
return new AbstractParser<DynamicMessage>() {
|
||||
@Override
|
||||
public DynamicMessage parsePartialFrom(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
Builder builder = newBuilder(type);
|
||||
try {
|
||||
builder.mergeFrom(input, extensionRegistry);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(builder.buildPartial());
|
||||
} catch (IOException e) {
|
||||
throw new InvalidProtocolBufferException(e).setUnfinishedMessage(builder.buildPartial());
|
||||
}
|
||||
return builder.buildPartial();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 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.");
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.");
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/** Builder for {@link DynamicMessage}s. */
|
||||
public static final class Builder extends AbstractMessage.Builder<Builder> {
|
||||
private final Descriptor type;
|
||||
private FieldSet.Builder<FieldDescriptor> fields;
|
||||
private final FieldDescriptor[] oneofCases;
|
||||
private UnknownFieldSet unknownFields;
|
||||
|
||||
/** Construct a {@code Builder} for the given type. */
|
||||
private Builder(Descriptor type) {
|
||||
this.type = type;
|
||||
this.fields = FieldSet.newBuilder();
|
||||
this.unknownFields = UnknownFieldSet.getDefaultInstance();
|
||||
this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Implementation of Message.Builder interface.
|
||||
|
||||
@Override
|
||||
public Builder clear() {
|
||||
fields = FieldSet.newBuilder();
|
||||
unknownFields = UnknownFieldSet.getDefaultInstance();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(Message other) {
|
||||
if (other instanceof DynamicMessage) {
|
||||
// This should be somewhat faster than calling super.mergeFrom().
|
||||
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
|
||||
if (otherDynamicMessage.type != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
}
|
||||
fields.mergeFrom(otherDynamicMessage.fields);
|
||||
mergeUnknownFields(otherDynamicMessage.unknownFields);
|
||||
for (int i = 0; i < oneofCases.length; i++) {
|
||||
if (oneofCases[i] == null) {
|
||||
oneofCases[i] = otherDynamicMessage.oneofCases[i];
|
||||
} else {
|
||||
if ((otherDynamicMessage.oneofCases[i] != null)
|
||||
&& (oneofCases[i] != otherDynamicMessage.oneofCases[i])) {
|
||||
fields.clearField(oneofCases[i]);
|
||||
oneofCases[i] = otherDynamicMessage.oneofCases[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
return super.mergeFrom(other);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage build() {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
new DynamicMessage(
|
||||
type, fields.build(), Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.build(),
|
||||
Arrays.copyOf(oneofCases, oneofCases.length),
|
||||
unknownFields))
|
||||
.asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage buildPartial() {
|
||||
// Set default values for all fields in a MapEntry.
|
||||
if (type.getOptions().getMapEntry()) {
|
||||
for (FieldDescriptor field : type.getFields()) {
|
||||
if (field.isOptional() && !fields.hasField(field)) {
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
fields.setField(field, getDefaultInstance(field.getMessageType()));
|
||||
} else {
|
||||
fields.setField(field, field.getDefaultValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMessage result =
|
||||
new DynamicMessage(
|
||||
type,
|
||||
fields.buildPartial(),
|
||||
Arrays.copyOf(oneofCases, oneofCases.length),
|
||||
unknownFields);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clone() {
|
||||
Builder result = new Builder(type);
|
||||
result.fields.mergeFrom(fields.build());
|
||||
result.mergeUnknownFields(unknownFields);
|
||||
System.arraycopy(oneofCases, 0, result.oneofCases, 0, oneofCases.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
// Check that all required fields are present.
|
||||
for (FieldDescriptor field : type.getFields()) {
|
||||
if (field.isRequired()) {
|
||||
if (!fields.hasField(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that embedded messages are initialized.
|
||||
return fields.isInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage getDefaultInstanceForType() {
|
||||
return getDefaultInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
return fields.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
|
||||
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"newBuilderForField is only valid for fields with message type.");
|
||||
}
|
||||
|
||||
return new Builder(field.getMessageType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOneof(OneofDescriptor oneof) {
|
||||
verifyOneofContainingType(oneof);
|
||||
FieldDescriptor field = oneofCases[oneof.getIndex()];
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
|
||||
verifyOneofContainingType(oneof);
|
||||
return oneofCases[oneof.getIndex()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clearOneof(OneofDescriptor oneof) {
|
||||
verifyOneofContainingType(oneof);
|
||||
FieldDescriptor field = oneofCases[oneof.getIndex()];
|
||||
if (field != null) {
|
||||
clearField(field);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
Object result = fields.getField(field);
|
||||
if (result == null) {
|
||||
if (field.isRepeated()) {
|
||||
result = Collections.emptyList();
|
||||
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
result = getDefaultInstance(field.getMessageType());
|
||||
} else {
|
||||
result = field.getDefaultValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setField(FieldDescriptor field, Object value) {
|
||||
verifyContainingType(field);
|
||||
// TODO(xiaofeng): This check should really be put in FieldSet.setField()
|
||||
// where all other such checks are done. However, currently
|
||||
// FieldSet.setField() permits Integer value for enum fields probably
|
||||
// because of some internal features we support. Should figure it out
|
||||
// and move this check to a more appropriate place.
|
||||
verifyType(field, value);
|
||||
OneofDescriptor oneofDescriptor = field.getContainingOneof();
|
||||
if (oneofDescriptor != null) {
|
||||
int index = oneofDescriptor.getIndex();
|
||||
FieldDescriptor oldField = oneofCases[index];
|
||||
if ((oldField != null) && (oldField != field)) {
|
||||
fields.clearField(oldField);
|
||||
}
|
||||
oneofCases[index] = field;
|
||||
} else if (field.getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) {
|
||||
if (!field.isRepeated()
|
||||
&& field.getJavaType() != FieldDescriptor.JavaType.MESSAGE
|
||||
&& value.equals(field.getDefaultValue())) {
|
||||
// In proto3, setting a field to its default value is equivalent to clearing the field.
|
||||
fields.clearField(field);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
fields.setField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clearField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
OneofDescriptor oneofDescriptor = field.getContainingOneof();
|
||||
if (oneofDescriptor != null) {
|
||||
int index = oneofDescriptor.getIndex();
|
||||
if (oneofCases[index] == field) {
|
||||
oneofCases[index] = null;
|
||||
}
|
||||
}
|
||||
fields.clearField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setRepeatedField(FieldDescriptor field, int index, Object value) {
|
||||
verifyContainingType(field);
|
||||
verifySingularValueType(field, value);
|
||||
fields.setRepeatedField(field, index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder addRepeatedField(FieldDescriptor field, Object value) {
|
||||
verifyContainingType(field);
|
||||
verifySingularValueType(field, value);
|
||||
fields.addRepeatedField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
|
||||
this.unknownFields = unknownFields;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
|
||||
this.unknownFields =
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that {@code value} is of the appropriate type, in addition to the checks already
|
||||
* performed by {@link FieldSet.Builder}.
|
||||
*/
|
||||
private void verifySingularValueType(FieldDescriptor field, Object value) {
|
||||
// Most type checks are performed by FieldSet.Builder, but FieldSet.Builder is more permissive
|
||||
// than generated Message.Builder subclasses, so we perform extra checks in this class so that
|
||||
// DynamicMessage.Builder's semantics more closely match the semantics of generated builders.
|
||||
switch (field.getType()) {
|
||||
case ENUM:
|
||||
checkNotNull(value);
|
||||
// FieldSet.Builder accepts Integer values for enum fields.
|
||||
if (!(value instanceof EnumValueDescriptor)) {
|
||||
throw new IllegalArgumentException(
|
||||
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
|
||||
}
|
||||
// TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
|
||||
// set incorrect EnumValueDescriptors.
|
||||
// EnumDescriptor fieldType = field.getEnumType();
|
||||
// EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
|
||||
// if (fieldType != fieldValueType) {
|
||||
// throw new IllegalArgumentException(String.format(
|
||||
// "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
|
||||
// fieldType.getFullName(), fieldValueType.getFullName()));
|
||||
// }
|
||||
break;
|
||||
case MESSAGE:
|
||||
// FieldSet.Builder accepts Message.Builder values for message fields.
|
||||
if (value instanceof Message.Builder) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Wrong object type used with protocol message reflection.\n"
|
||||
+ "Field number: %d, field java type: %s, value type: %s\n",
|
||||
field.getNumber(),
|
||||
field.getLiteType().getJavaType(),
|
||||
value.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that {@code value} is of the appropriate type, in addition to the checks already
|
||||
* performed by {@link FieldSet.Builder}.
|
||||
*/
|
||||
private void verifyType(FieldDescriptor field, Object value) {
|
||||
if (field.isRepeated()) {
|
||||
for (Object item : (List<?>) value) {
|
||||
verifySingularValueType(field, item);
|
||||
}
|
||||
} else {
|
||||
verifySingularValueType(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
// Error messages chosen for parity with GeneratedMessage.getFieldBuilder.
|
||||
if (field.isMapField()) {
|
||||
throw new UnsupportedOperationException("Nested builder not supported for map fields.");
|
||||
}
|
||||
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new UnsupportedOperationException("getFieldBuilder() called on a non-Message type.");
|
||||
}
|
||||
|
||||
Object existingValue = fields.getFieldAllowBuilders(field);
|
||||
Message.Builder builder =
|
||||
existingValue == null
|
||||
? new Builder(field.getMessageType())
|
||||
: toMessageBuilder(existingValue);
|
||||
fields.setField(field, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(
|
||||
FieldDescriptor field, int index) {
|
||||
verifyContainingType(field);
|
||||
// Error messages chosen for parity with GeneratedMessage.getRepeatedFieldBuilder.
|
||||
if (field.isMapField()) {
|
||||
throw new UnsupportedOperationException("Map fields cannot be repeated");
|
||||
}
|
||||
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"getRepeatedFieldBuilder() called on a non-Message type.");
|
||||
}
|
||||
|
||||
Message.Builder builder =
|
||||
toMessageBuilder(fields.getRepeatedFieldAllowBuilders(field, index));
|
||||
fields.setRepeatedField(field, index, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static Message.Builder toMessageBuilder(Object o) {
|
||||
if (o instanceof Message.Builder) {
|
||||
return (Message.Builder) o;
|
||||
}
|
||||
|
||||
if (o instanceof LazyField) {
|
||||
o = ((LazyField) o).getValue();
|
||||
}
|
||||
if (o instanceof Message) {
|
||||
return ((Message) o).toBuilder();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot convert %s to Message.Builder", o.getClass()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates a public API that can change at any time, and has no guarantee of API stability and
|
||||
* backward-compatibility.
|
||||
*
|
||||
* <p>Usage guidelines:
|
||||
*
|
||||
* <ol>
|
||||
* <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
|
||||
})
|
||||
@Documented
|
||||
public @interface ExperimentalApi {
|
||||
/** Context information such as links to discussion thread, tracking issue etc. */
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
// TODO(chrisn): Change ContainingType to extend Message
|
||||
/**
|
||||
* Interface that generated extensions implement.
|
||||
*
|
||||
* @author liujisi@google.com (Jisi Liu)
|
||||
*/
|
||||
public abstract class Extension<ContainingType extends MessageLite, Type>
|
||||
extends ExtensionLite<ContainingType, Type> {
|
||||
// TODO(chrisn): Add package-private constructor.
|
||||
|
||||
/** {@inheritDoc} Overridden to return {@link Message} instead of {@link MessageLite}. */
|
||||
@Override
|
||||
public abstract Message getMessageDefaultInstance();
|
||||
|
||||
/** Returns the descriptor of the extension. */
|
||||
public abstract Descriptors.FieldDescriptor getDescriptor();
|
||||
|
||||
/** Returns whether or not this extension is a Lite Extension. */
|
||||
@Override
|
||||
final boolean isLite() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All the methods below are extension implementation details.
|
||||
|
||||
/** The API type that the extension is used for. */
|
||||
protected enum ExtensionType {
|
||||
IMMUTABLE,
|
||||
MUTABLE,
|
||||
PROTO1,
|
||||
}
|
||||
|
||||
protected abstract ExtensionType getExtensionType();
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Lite interface that generated extensions implement.
|
||||
*
|
||||
* <p>Methods are for use by generated code only. You can hold a reference to extensions using this
|
||||
* type name.
|
||||
*/
|
||||
public abstract class ExtensionLite<ContainingType extends MessageLite, Type> {
|
||||
|
||||
/** Returns the field number of the extension. */
|
||||
public abstract int getNumber();
|
||||
|
||||
/** Returns the type of the field. */
|
||||
public abstract WireFormat.FieldType getLiteType();
|
||||
|
||||
/** Returns whether it is a repeated field. */
|
||||
public abstract boolean isRepeated();
|
||||
|
||||
/** Returns the default value of the extension field. */
|
||||
public abstract Type getDefaultValue();
|
||||
|
||||
/** Returns the default instance of the extension field, if it's a message extension. */
|
||||
public abstract MessageLite getMessageDefaultInstance();
|
||||
|
||||
/** Returns whether or not this extension is a Lite Extension. */
|
||||
boolean isLite() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
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.
|
||||
*
|
||||
* <p>For example, if you had the {@code .proto} file:
|
||||
*
|
||||
* <pre>
|
||||
* option java_class = "MyProto";
|
||||
*
|
||||
* message Foo {
|
||||
* extensions 1000 to max;
|
||||
* }
|
||||
*
|
||||
* extend Foo {
|
||||
* optional int32 bar;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Then you might write code like:
|
||||
*
|
||||
* <pre>
|
||||
* ExtensionRegistry registry = ExtensionRegistry.newInstance();
|
||||
* registry.add(MyProto.bar);
|
||||
* MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
|
||||
* </pre>
|
||||
*
|
||||
* <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>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
|
||||
*/
|
||||
public class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
/** Construct a new, empty instance. */
|
||||
public static ExtensionRegistry newInstance() {
|
||||
return new ExtensionRegistry();
|
||||
}
|
||||
|
||||
/** Get the unmodifiable singleton empty instance. */
|
||||
public static ExtensionRegistry getEmptyRegistry() {
|
||||
return EMPTY_REGISTRY;
|
||||
}
|
||||
|
||||
|
||||
/** Returns an unmodifiable view of the registry. */
|
||||
@Override
|
||||
public ExtensionRegistry getUnmodifiable() {
|
||||
return new ExtensionRegistry(this);
|
||||
}
|
||||
|
||||
/** A (Descriptor, Message) pair, returned by lookup methods. */
|
||||
public static final class ExtensionInfo {
|
||||
/** The extension's descriptor. */
|
||||
public final FieldDescriptor descriptor;
|
||||
|
||||
/**
|
||||
* A default instance of the extension's type, if it has a message type. Otherwise, {@code
|
||||
* null}.
|
||||
*/
|
||||
public final Message defaultInstance;
|
||||
|
||||
private ExtensionInfo(final FieldDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
defaultInstance = null;
|
||||
}
|
||||
|
||||
private ExtensionInfo(final FieldDescriptor descriptor, final Message defaultInstance) {
|
||||
this.descriptor = descriptor;
|
||||
this.defaultInstance = defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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
|
||||
public ExtensionInfo findExtensionByNumber(
|
||||
final Descriptor containingType, final int fieldNumber) {
|
||||
return findImmutableExtensionByNumber(containingType, fieldNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number for immutable APIs.
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number for mutable APIs.
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Set<ExtensionInfo> getAllMutableExtensionsByExtendedType(final String fullName) {
|
||||
HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
|
||||
for (DescriptorIntPair pair : mutableExtensionsByNumber.keySet()) {
|
||||
if (pair.descriptor.getFullName().equals(fullName)) {
|
||||
extensions.add(mutableExtensionsByNumber.get(pair));
|
||||
}
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Set<ExtensionInfo> getAllImmutableExtensionsByExtendedType(final String fullName) {
|
||||
HashSet<ExtensionInfo> extensions = new HashSet<ExtensionInfo>();
|
||||
for (DescriptorIntPair pair : immutableExtensionsByNumber.keySet()) {
|
||||
if (pair.descriptor.getFullName().equals(fullName)) {
|
||||
extensions.add(immutableExtensionsByNumber.get(pair));
|
||||
}
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
// do not support other extension types. ignore
|
||||
return;
|
||||
}
|
||||
add(newExtensionInfo(extension), extension.getExtensionType());
|
||||
}
|
||||
|
||||
/** Add an extension from a generated file to the registry. */
|
||||
public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
|
||||
add((Extension<?, ?>) extension);
|
||||
}
|
||||
|
||||
static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
|
||||
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());
|
||||
}
|
||||
return new ExtensionInfo(
|
||||
extension.getDescriptor(), (Message) extension.getMessageDefaultInstance());
|
||||
} else {
|
||||
return new ExtensionInfo(extension.getDescriptor(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add a non-message-type extension to the registry by descriptor. */
|
||||
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.");
|
||||
}
|
||||
ExtensionInfo info = new ExtensionInfo(type, null);
|
||||
add(info, Extension.ExtensionType.IMMUTABLE);
|
||||
add(info, Extension.ExtensionType.MUTABLE);
|
||||
}
|
||||
|
||||
/** Add a message-type extension to the registry by descriptor. */
|
||||
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.");
|
||||
}
|
||||
add(new ExtensionInfo(type, defaultInstance), Extension.ExtensionType.IMMUTABLE);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Private stuff.
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
private ExtensionRegistry(ExtensionRegistry other) {
|
||||
super(other);
|
||||
this.immutableExtensionsByName = Collections.unmodifiableMap(other.immutableExtensionsByName);
|
||||
this.mutableExtensionsByName = Collections.unmodifiableMap(other.mutableExtensionsByName);
|
||||
this.immutableExtensionsByNumber =
|
||||
Collections.unmodifiableMap(other.immutableExtensionsByNumber);
|
||||
this.mutableExtensionsByNumber = Collections.unmodifiableMap(other.mutableExtensionsByNumber);
|
||||
}
|
||||
|
||||
private final Map<String, ExtensionInfo> immutableExtensionsByName;
|
||||
private final Map<String, ExtensionInfo> mutableExtensionsByName;
|
||||
private final Map<DescriptorIntPair, ExtensionInfo> immutableExtensionsByNumber;
|
||||
private final Map<DescriptorIntPair, ExtensionInfo> mutableExtensionsByNumber;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
static final ExtensionRegistry EMPTY_REGISTRY = new ExtensionRegistry(true);
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
Map<String, ExtensionInfo> extensionsByName;
|
||||
Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
|
||||
switch (extensionType) {
|
||||
case IMMUTABLE:
|
||||
extensionsByName = immutableExtensionsByName;
|
||||
extensionsByNumber = immutableExtensionsByNumber;
|
||||
break;
|
||||
case MUTABLE:
|
||||
extensionsByName = mutableExtensionsByName;
|
||||
extensionsByNumber = mutableExtensionsByNumber;
|
||||
break;
|
||||
default:
|
||||
// Ignore the unknown supported type.
|
||||
return;
|
||||
}
|
||||
|
||||
extensionsByName.put(extension.descriptor.getFullName(), extension);
|
||||
extensionsByNumber.put(
|
||||
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()) {
|
||||
// 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.
|
||||
extensionsByName.put(field.getMessageType().getFullName(), extension);
|
||||
}
|
||||
}
|
||||
|
||||
/** A (GenericDescriptor, int) pair, used as a map key. */
|
||||
private static final class DescriptorIntPair {
|
||||
private final Descriptor descriptor;
|
||||
private final int number;
|
||||
|
||||
DescriptorIntPair(final Descriptor descriptor, final int number) {
|
||||
this.descriptor = descriptor;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
return descriptor == other.descriptor && number == other.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import 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}.
|
||||
*/
|
||||
final class ExtensionRegistryFactory {
|
||||
|
||||
static final String FULL_REGISTRY_CLASS_NAME = "com.google.protobuf.ExtensionRegistry";
|
||||
|
||||
/* Visible for Testing
|
||||
@Nullable */
|
||||
static final Class<?> EXTENSION_REGISTRY_CLASS = reflectExtensionRegistry();
|
||||
|
||||
static Class<?> reflectExtensionRegistry() {
|
||||
try {
|
||||
return Class.forName(FULL_REGISTRY_CLASS_NAME);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// The exception allocation is potentially expensive on Android (where it can be triggered
|
||||
// many times at start up). Is there a way to ameliorate this?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Construct a new, empty instance. */
|
||||
public static ExtensionRegistryLite create() {
|
||||
ExtensionRegistryLite result = invokeSubclassFactory("newInstance");
|
||||
|
||||
return result != null ? result : new ExtensionRegistryLite();
|
||||
}
|
||||
|
||||
/** Get the unmodifiable singleton empty instance. */
|
||||
public static ExtensionRegistryLite createEmpty() {
|
||||
ExtensionRegistryLite result = invokeSubclassFactory("getEmptyRegistry");
|
||||
|
||||
return result != null ? result : EMPTY_REGISTRY_LITE;
|
||||
}
|
||||
|
||||
|
||||
static boolean isFullRegistry(ExtensionRegistryLite registry) {
|
||||
return EXTENSION_REGISTRY_CLASS != null
|
||||
&& EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
|
||||
}
|
||||
|
||||
private static final ExtensionRegistryLite invokeSubclassFactory(String methodName) {
|
||||
if (EXTENSION_REGISTRY_CLASS == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (ExtensionRegistryLite)
|
||||
EXTENSION_REGISTRY_CLASS.getDeclaredMethod(methodName).invoke(null);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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:
|
||||
*
|
||||
* <pre>
|
||||
* Extended type Inner type Extension Use registry
|
||||
* =======================================================================
|
||||
* lite lite lite ExtensionRegistryLite
|
||||
* lite regular lite ExtensionRegistry
|
||||
* 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.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class ExtensionRegistryLite {
|
||||
|
||||
// Set true to enable lazy parsing feature for MessageSet.
|
||||
//
|
||||
// TODO(xiangl): Now we use a global flag to control whether enable lazy
|
||||
// parsing feature for MessageSet, which may be too crude for some
|
||||
// applications. Need to support this feature on smaller granularity.
|
||||
private static volatile boolean eagerlyParseMessageSets = false;
|
||||
|
||||
// short circuit the ExtensionRegistryFactory via assumevalues trickery
|
||||
@SuppressWarnings("JavaOptionalSuggestions")
|
||||
private static boolean doFullRuntimeInheritanceCheck = true;
|
||||
|
||||
// Visible for testing.
|
||||
static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
|
||||
|
||||
private static class ExtensionClassHolder {
|
||||
static final Class<?> INSTANCE = resolveExtensionClass();
|
||||
|
||||
static Class<?> resolveExtensionClass() {
|
||||
try {
|
||||
return Class.forName(EXTENSION_CLASS_NAME);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// See comment in ExtensionRegistryFactory on the potential expense of this.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEagerlyParseMessageSets() {
|
||||
return eagerlyParseMessageSets;
|
||||
}
|
||||
|
||||
public static void setEagerlyParseMessageSets(boolean isEagerlyParse) {
|
||||
eagerlyParseMessageSets = isEagerlyParse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new, empty instance.
|
||||
*
|
||||
* <p>This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are
|
||||
* available.
|
||||
*/
|
||||
public static ExtensionRegistryLite newInstance() {
|
||||
return doFullRuntimeInheritanceCheck
|
||||
? ExtensionRegistryFactory.create()
|
||||
: new ExtensionRegistryLite();
|
||||
}
|
||||
|
||||
private static volatile ExtensionRegistryLite emptyRegistry;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
if (!doFullRuntimeInheritanceCheck) {
|
||||
return EMPTY_REGISTRY_LITE;
|
||||
}
|
||||
ExtensionRegistryLite result = emptyRegistry;
|
||||
if (result == null) {
|
||||
synchronized (ExtensionRegistryLite.class) {
|
||||
result = emptyRegistry;
|
||||
if (result == null) {
|
||||
result = emptyRegistry = ExtensionRegistryFactory.createEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Returns an unmodifiable view of the registry. */
|
||||
public ExtensionRegistryLite getUnmodifiable() {
|
||||
return new ExtensionRegistryLite(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number.
|
||||
*
|
||||
* @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) {
|
||||
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
|
||||
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) {
|
||||
extensionsByNumber.put(
|
||||
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}.
|
||||
*/
|
||||
public final void add(ExtensionLite<?, ?> extension) {
|
||||
if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
|
||||
add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
|
||||
}
|
||||
if (doFullRuntimeInheritanceCheck && ExtensionRegistryFactory.isFullRegistry(this)) {
|
||||
try {
|
||||
this.getClass().getMethod("add", ExtensionClassHolder.INSTANCE).invoke(this, extension);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Could not invoke ExtensionRegistry#add for %s", extension), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Private stuff.
|
||||
|
||||
// Constructors are package-private so that ExtensionRegistry can subclass
|
||||
// this.
|
||||
|
||||
ExtensionRegistryLite() {
|
||||
this.extensionsByNumber =
|
||||
new HashMap<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ObjectIntPair, GeneratedMessageLite.GeneratedExtension<?, ?>>
|
||||
extensionsByNumber;
|
||||
|
||||
ExtensionRegistryLite(boolean empty) {
|
||||
this.extensionsByNumber = Collections.emptyMap();
|
||||
}
|
||||
|
||||
/** A (Object, int) pair, used as a map key. */
|
||||
private static final class ObjectIntPair {
|
||||
private final Object object;
|
||||
private final int number;
|
||||
|
||||
ObjectIntPair(final Object object, final int number) {
|
||||
this.object = object;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
return object == other.object && number == other.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@CheckReturnValue
|
||||
abstract class ExtensionSchema<T extends FieldSet.FieldDescriptorLite<T>> {
|
||||
|
||||
/** Returns true for messages that support extensions. */
|
||||
abstract boolean hasExtensions(MessageLite prototype);
|
||||
|
||||
/** Returns the extension {@link FieldSet} for the message instance. */
|
||||
abstract FieldSet<T> getExtensions(Object message);
|
||||
|
||||
/** Replaces the extension {@link FieldSet} for the message instance. */
|
||||
abstract void setExtensions(Object message, FieldSet<T> extensions);
|
||||
|
||||
/** Returns the extension {@link FieldSet} and ensures it's mutable. */
|
||||
abstract FieldSet<T> getMutableExtensions(Object message);
|
||||
|
||||
/** Marks the extension {@link FieldSet} as immutable. */
|
||||
abstract void makeImmutable(Object message);
|
||||
|
||||
/**
|
||||
* Parses an extension. Returns the passed-in unknownFields parameter if no unknown enum value is
|
||||
* found or a modified unknownFields (a new instance if the passed-in unknownFields is null)
|
||||
* containing unknown enum values found while parsing.
|
||||
*
|
||||
* @param <UT> The type used to store unknown fields. It's either UnknownFieldSet in full runtime
|
||||
* or UnknownFieldSetLite in lite runtime.
|
||||
*/
|
||||
abstract <UT, UB> UB parseExtension(
|
||||
Object containerMessage,
|
||||
Reader reader,
|
||||
Object extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<T> extensions,
|
||||
UB unknownFields,
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema)
|
||||
throws IOException;
|
||||
|
||||
/** Gets the field number of an extension entry. */
|
||||
abstract int extensionNumber(Map.Entry<?, ?> extension);
|
||||
|
||||
/** Serializes one extension entry. */
|
||||
abstract void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException;
|
||||
|
||||
/** Finds an extension by field number. */
|
||||
abstract Object findExtensionByNumber(
|
||||
ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number);
|
||||
|
||||
/** Parses a length-prefixed MessageSet item from the reader. */
|
||||
abstract void parseLengthPrefixedMessageSetItem(
|
||||
Reader reader,
|
||||
Object extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<T> extensions)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Parses the entire content of a {@link ByteString} as one MessageSet item. Unlike {@link
|
||||
* #parseLengthPrefixedMessageSetItem}, there isn't a length-prefix.
|
||||
*/
|
||||
abstract void parseMessageSetItem(
|
||||
ByteString data,
|
||||
Object extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<T> extensions)
|
||||
throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,548 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final class ExtensionSchemaFull extends ExtensionSchema<FieldDescriptor> {
|
||||
|
||||
private static final long EXTENSION_FIELD_OFFSET = getExtensionsFieldOffset();
|
||||
|
||||
private static <T> long getExtensionsFieldOffset() {
|
||||
try {
|
||||
Field field = GeneratedMessageV3.ExtendableMessage.class.getDeclaredField("extensions");
|
||||
return UnsafeUtil.objectFieldOffset(field);
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalStateException("Unable to lookup extension field offset");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasExtensions(MessageLite prototype) {
|
||||
return prototype instanceof GeneratedMessageV3.ExtendableMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldSet<FieldDescriptor> getExtensions(Object message) {
|
||||
return (FieldSet<FieldDescriptor>) UnsafeUtil.getObject(message, EXTENSION_FIELD_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setExtensions(Object message, FieldSet<FieldDescriptor> extensions) {
|
||||
UnsafeUtil.putObject(message, EXTENSION_FIELD_OFFSET, extensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
FieldSet<FieldDescriptor> getMutableExtensions(Object message) {
|
||||
FieldSet<FieldDescriptor> extensions = getExtensions(message);
|
||||
if (extensions.isImmutable()) {
|
||||
extensions = extensions.clone();
|
||||
setExtensions(message, extensions);
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
void makeImmutable(Object message) {
|
||||
getExtensions(message).makeImmutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
<UT, UB> UB parseExtension(
|
||||
Object containerMessage,
|
||||
Reader reader,
|
||||
Object extensionObject,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<FieldDescriptor> extensions,
|
||||
UB unknownFields,
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema)
|
||||
throws IOException {
|
||||
ExtensionRegistry.ExtensionInfo extension = (ExtensionRegistry.ExtensionInfo) extensionObject;
|
||||
int fieldNumber = extension.descriptor.getNumber();
|
||||
|
||||
if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) {
|
||||
Object value = null;
|
||||
switch (extension.descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
{
|
||||
List<Double> list = new ArrayList<Double>();
|
||||
reader.readDoubleList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FLOAT:
|
||||
{
|
||||
List<Float> list = new ArrayList<Float>();
|
||||
reader.readFloatList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case INT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case UINT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readUInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case INT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FIXED64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readFixed64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FIXED32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readFixed32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case BOOL:
|
||||
{
|
||||
List<Boolean> list = new ArrayList<Boolean>();
|
||||
reader.readBoolList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case UINT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readUInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SFIXED32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readSFixed32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SFIXED64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readSFixed64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SINT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readSInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SINT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readSInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readEnumList(list);
|
||||
List<EnumValueDescriptor> enumList = new ArrayList<EnumValueDescriptor>();
|
||||
for (int number : list) {
|
||||
EnumValueDescriptor enumDescriptor =
|
||||
extension.descriptor.getEnumType().findValueByNumber(number);
|
||||
if (enumDescriptor != null) {
|
||||
enumList.add(enumDescriptor);
|
||||
} else {
|
||||
unknownFields =
|
||||
SchemaUtil.storeUnknownEnum(
|
||||
containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
||||
}
|
||||
}
|
||||
value = enumList;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Type cannot be packed: " + extension.descriptor.getLiteType());
|
||||
}
|
||||
extensions.setField(extension.descriptor, value);
|
||||
} else {
|
||||
Object value = null;
|
||||
// Enum is a special case because unknown enum values will be put into UnknownFieldSetLite.
|
||||
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
|
||||
int number = reader.readInt32();
|
||||
Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number);
|
||||
if (enumValue == null) {
|
||||
return SchemaUtil.storeUnknownEnum(
|
||||
containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
||||
}
|
||||
value = enumValue;
|
||||
} else {
|
||||
switch (extension.descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
value = reader.readDouble();
|
||||
break;
|
||||
case FLOAT:
|
||||
value = reader.readFloat();
|
||||
break;
|
||||
case INT64:
|
||||
value = reader.readInt64();
|
||||
break;
|
||||
case UINT64:
|
||||
value = reader.readUInt64();
|
||||
break;
|
||||
case INT32:
|
||||
value = reader.readInt32();
|
||||
break;
|
||||
case FIXED64:
|
||||
value = reader.readFixed64();
|
||||
break;
|
||||
case FIXED32:
|
||||
value = reader.readFixed32();
|
||||
break;
|
||||
case BOOL:
|
||||
value = reader.readBool();
|
||||
break;
|
||||
case BYTES:
|
||||
value = reader.readBytes();
|
||||
break;
|
||||
case UINT32:
|
||||
value = reader.readUInt32();
|
||||
break;
|
||||
case SFIXED32:
|
||||
value = reader.readSFixed32();
|
||||
break;
|
||||
case SFIXED64:
|
||||
value = reader.readSFixed64();
|
||||
break;
|
||||
case SINT32:
|
||||
value = reader.readSInt32();
|
||||
break;
|
||||
case SINT64:
|
||||
value = reader.readSInt64();
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
value = reader.readString();
|
||||
break;
|
||||
case GROUP:
|
||||
value = reader.readGroup(extension.defaultInstance.getClass(), extensionRegistry);
|
||||
break;
|
||||
|
||||
case MESSAGE:
|
||||
value = reader.readMessage(extension.defaultInstance.getClass(), extensionRegistry);
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
throw new IllegalStateException("Shouldn't reach here.");
|
||||
}
|
||||
}
|
||||
if (extension.descriptor.isRepeated()) {
|
||||
extensions.addRepeatedField(extension.descriptor, value);
|
||||
} else {
|
||||
switch (extension.descriptor.getLiteType()) {
|
||||
case MESSAGE:
|
||||
case GROUP:
|
||||
Object oldValue = extensions.getField(extension.descriptor);
|
||||
if (oldValue != null) {
|
||||
value = Internal.mergeMessage(oldValue, value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
extensions.setField(extension.descriptor, value);
|
||||
}
|
||||
}
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
int extensionNumber(Map.Entry<?, ?> extension) {
|
||||
FieldDescriptor descriptor = (FieldDescriptor) extension.getKey();
|
||||
return descriptor.getNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException {
|
||||
FieldDescriptor descriptor = (FieldDescriptor) extension.getKey();
|
||||
if (descriptor.isRepeated()) {
|
||||
switch (descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
SchemaUtil.writeDoubleList(
|
||||
descriptor.getNumber(),
|
||||
(List<Double>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FLOAT:
|
||||
SchemaUtil.writeFloatList(
|
||||
descriptor.getNumber(),
|
||||
(List<Float>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case INT64:
|
||||
SchemaUtil.writeInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case UINT64:
|
||||
SchemaUtil.writeUInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case INT32:
|
||||
SchemaUtil.writeInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FIXED64:
|
||||
SchemaUtil.writeFixed64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FIXED32:
|
||||
SchemaUtil.writeFixed32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case BOOL:
|
||||
SchemaUtil.writeBoolList(
|
||||
descriptor.getNumber(),
|
||||
(List<Boolean>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case BYTES:
|
||||
SchemaUtil.writeBytesList(
|
||||
descriptor.getNumber(), (List<ByteString>) extension.getValue(), writer);
|
||||
break;
|
||||
case UINT32:
|
||||
SchemaUtil.writeUInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SFIXED32:
|
||||
SchemaUtil.writeSFixed32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SFIXED64:
|
||||
SchemaUtil.writeSFixed64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SINT32:
|
||||
SchemaUtil.writeSInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SINT64:
|
||||
SchemaUtil.writeSInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case ENUM:
|
||||
{
|
||||
List<EnumValueDescriptor> enumList = (List<EnumValueDescriptor>) extension.getValue();
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
for (EnumValueDescriptor d : enumList) {
|
||||
list.add(d.getNumber());
|
||||
}
|
||||
SchemaUtil.writeInt32List(descriptor.getNumber(), list, writer, descriptor.isPacked());
|
||||
break;
|
||||
}
|
||||
case STRING:
|
||||
SchemaUtil.writeStringList(
|
||||
descriptor.getNumber(), (List<String>) extension.getValue(), writer);
|
||||
break;
|
||||
case GROUP:
|
||||
SchemaUtil.writeGroupList(descriptor.getNumber(), (List<?>) extension.getValue(), writer);
|
||||
break;
|
||||
case MESSAGE:
|
||||
SchemaUtil.writeMessageList(
|
||||
descriptor.getNumber(), (List<?>) extension.getValue(), writer);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
writer.writeDouble(descriptor.getNumber(), (Double) extension.getValue());
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.writeFloat(descriptor.getNumber(), (Float) extension.getValue());
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case UINT64:
|
||||
writer.writeUInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case INT32:
|
||||
writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case FIXED64:
|
||||
writer.writeFixed64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case FIXED32:
|
||||
writer.writeFixed32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case BOOL:
|
||||
writer.writeBool(descriptor.getNumber(), (Boolean) extension.getValue());
|
||||
break;
|
||||
case BYTES:
|
||||
writer.writeBytes(descriptor.getNumber(), (ByteString) extension.getValue());
|
||||
break;
|
||||
case UINT32:
|
||||
writer.writeUInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SFIXED32:
|
||||
writer.writeSFixed32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SFIXED64:
|
||||
writer.writeSFixed64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case SINT32:
|
||||
writer.writeSInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SINT64:
|
||||
writer.writeSInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case ENUM:
|
||||
writer.writeInt32(
|
||||
descriptor.getNumber(), ((EnumValueDescriptor) extension.getValue()).getNumber());
|
||||
break;
|
||||
case STRING:
|
||||
writer.writeString(descriptor.getNumber(), (String) extension.getValue());
|
||||
break;
|
||||
case GROUP:
|
||||
writer.writeGroup(descriptor.getNumber(), extension.getValue());
|
||||
break;
|
||||
case MESSAGE:
|
||||
writer.writeMessage(descriptor.getNumber(), extension.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object findExtensionByNumber(
|
||||
ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number) {
|
||||
return ((ExtensionRegistry) extensionRegistry)
|
||||
.findImmutableExtensionByNumber(((Message) defaultInstance).getDescriptorForType(), number);
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseLengthPrefixedMessageSetItem(
|
||||
Reader reader,
|
||||
Object extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<FieldDescriptor> extensions)
|
||||
throws IOException {
|
||||
ExtensionRegistry.ExtensionInfo extensionInfo = (ExtensionRegistry.ExtensionInfo) extension;
|
||||
|
||||
if (ExtensionRegistryLite.isEagerlyParseMessageSets()) {
|
||||
Object value =
|
||||
reader.readMessage(extensionInfo.defaultInstance.getClass(), extensionRegistry);
|
||||
extensions.setField(extensionInfo.descriptor, value);
|
||||
} else {
|
||||
extensions.setField(
|
||||
extensionInfo.descriptor,
|
||||
new LazyField(extensionInfo.defaultInstance, extensionRegistry, reader.readBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseMessageSetItem(
|
||||
ByteString data,
|
||||
Object extension,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<FieldDescriptor> extensions)
|
||||
throws IOException {
|
||||
ExtensionRegistry.ExtensionInfo extensionInfo = (ExtensionRegistry.ExtensionInfo) extension;
|
||||
Object value = extensionInfo.defaultInstance.newBuilderForType().buildPartial();
|
||||
|
||||
if (ExtensionRegistryLite.isEagerlyParseMessageSets()) {
|
||||
Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(data.toByteArray()), true);
|
||||
Protobuf.getInstance().mergeFrom(value, reader, extensionRegistry);
|
||||
extensions.setField(extensionInfo.descriptor, value);
|
||||
|
||||
if (reader.getFieldNumber() != Reader.READ_DONE) {
|
||||
throw InvalidProtocolBufferException.invalidEndTag();
|
||||
}
|
||||
} else {
|
||||
extensions.setField(
|
||||
extensionInfo.descriptor,
|
||||
new LazyField(extensionInfo.defaultInstance, extensionRegistry, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.GeneratedMessageLite.ExtensionDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@CheckReturnValue
|
||||
@SuppressWarnings("unchecked")
|
||||
final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
|
||||
|
||||
@Override
|
||||
boolean hasExtensions(MessageLite prototype) {
|
||||
return prototype instanceof GeneratedMessageLite.ExtendableMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
FieldSet<ExtensionDescriptor> getExtensions(Object message) {
|
||||
return ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setExtensions(Object message, FieldSet<ExtensionDescriptor> extensions) {
|
||||
((GeneratedMessageLite.ExtendableMessage<?, ?>) message).extensions = extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
FieldSet<ExtensionDescriptor> getMutableExtensions(Object message) {
|
||||
return ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
void makeImmutable(Object message) {
|
||||
getExtensions(message).makeImmutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
<UT, UB> UB parseExtension(
|
||||
Object containerMessage,
|
||||
Reader reader,
|
||||
Object extensionObject,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<ExtensionDescriptor> extensions,
|
||||
UB unknownFields,
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema)
|
||||
throws IOException {
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?> extension =
|
||||
(GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject;
|
||||
int fieldNumber = extension.getNumber();
|
||||
|
||||
if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) {
|
||||
Object value = null;
|
||||
switch (extension.getLiteType()) {
|
||||
case DOUBLE:
|
||||
{
|
||||
List<Double> list = new ArrayList<Double>();
|
||||
reader.readDoubleList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FLOAT:
|
||||
{
|
||||
List<Float> list = new ArrayList<Float>();
|
||||
reader.readFloatList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case INT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case UINT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readUInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case INT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FIXED64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readFixed64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case FIXED32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readFixed32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case BOOL:
|
||||
{
|
||||
List<Boolean> list = new ArrayList<Boolean>();
|
||||
reader.readBoolList(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case UINT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readUInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SFIXED32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readSFixed32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SFIXED64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readSFixed64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SINT32:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readSInt32List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case SINT64:
|
||||
{
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
reader.readSInt64List(list);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
{
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
reader.readEnumList(list);
|
||||
unknownFields =
|
||||
SchemaUtil.filterUnknownEnumList(
|
||||
containerMessage,
|
||||
fieldNumber,
|
||||
list,
|
||||
extension.descriptor.getEnumType(),
|
||||
unknownFields,
|
||||
unknownFieldSchema);
|
||||
value = list;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Type cannot be packed: " + extension.descriptor.getLiteType());
|
||||
}
|
||||
extensions.setField(extension.descriptor, value);
|
||||
} else {
|
||||
Object value = null;
|
||||
// Enum is a special case because unknown enum values will be put into UnknownFieldSetLite.
|
||||
if (extension.getLiteType() == WireFormat.FieldType.ENUM) {
|
||||
int number = reader.readInt32();
|
||||
Object enumValue = extension.descriptor.getEnumType().findValueByNumber(number);
|
||||
if (enumValue == null) {
|
||||
return SchemaUtil.storeUnknownEnum(
|
||||
containerMessage, fieldNumber, number, unknownFields, unknownFieldSchema);
|
||||
}
|
||||
// Note, we store the integer value instead of the actual enum object in FieldSet.
|
||||
// This is also different from full-runtime where we store EnumValueDescriptor.
|
||||
value = number;
|
||||
} else {
|
||||
switch (extension.getLiteType()) {
|
||||
case DOUBLE:
|
||||
value = reader.readDouble();
|
||||
break;
|
||||
case FLOAT:
|
||||
value = reader.readFloat();
|
||||
break;
|
||||
case INT64:
|
||||
value = reader.readInt64();
|
||||
break;
|
||||
case UINT64:
|
||||
value = reader.readUInt64();
|
||||
break;
|
||||
case INT32:
|
||||
value = reader.readInt32();
|
||||
break;
|
||||
case FIXED64:
|
||||
value = reader.readFixed64();
|
||||
break;
|
||||
case FIXED32:
|
||||
value = reader.readFixed32();
|
||||
break;
|
||||
case BOOL:
|
||||
value = reader.readBool();
|
||||
break;
|
||||
case BYTES:
|
||||
value = reader.readBytes();
|
||||
break;
|
||||
case UINT32:
|
||||
value = reader.readUInt32();
|
||||
break;
|
||||
case SFIXED32:
|
||||
value = reader.readSFixed32();
|
||||
break;
|
||||
case SFIXED64:
|
||||
value = reader.readSFixed64();
|
||||
break;
|
||||
case SINT32:
|
||||
value = reader.readSInt32();
|
||||
break;
|
||||
case SINT64:
|
||||
value = reader.readSInt64();
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
value = reader.readString();
|
||||
break;
|
||||
case GROUP:
|
||||
// Special case handling for non-repeated sub-messages: merge in-place rather than
|
||||
// building up new sub-messages and merging those, which is too slow.
|
||||
// TODO(b/249368670): clean this up
|
||||
if (!extension.isRepeated()) {
|
||||
Object oldValue = extensions.getField(extension.descriptor);
|
||||
if (oldValue instanceof GeneratedMessageLite) {
|
||||
Schema extSchema = Protobuf.getInstance().schemaFor(oldValue);
|
||||
if (!((GeneratedMessageLite<?, ?>) oldValue).isMutable()) {
|
||||
Object newValue = extSchema.newInstance();
|
||||
extSchema.mergeFrom(newValue, oldValue);
|
||||
extensions.setField(extension.descriptor, newValue);
|
||||
oldValue = newValue;
|
||||
}
|
||||
reader.mergeGroupField(oldValue, extSchema, extensionRegistry);
|
||||
return unknownFields;
|
||||
}
|
||||
}
|
||||
value =
|
||||
reader.readGroup(
|
||||
extension.getMessageDefaultInstance().getClass(), extensionRegistry);
|
||||
break;
|
||||
|
||||
case MESSAGE:
|
||||
// Special case handling for non-repeated sub-messages: merge in-place rather than
|
||||
// building up new sub-messages and merging those, which is too slow.
|
||||
// TODO(b/249368670): clean this up
|
||||
if (!extension.isRepeated()) {
|
||||
Object oldValue = extensions.getField(extension.descriptor);
|
||||
if (oldValue instanceof GeneratedMessageLite) {
|
||||
Schema extSchema = Protobuf.getInstance().schemaFor(oldValue);
|
||||
if (!((GeneratedMessageLite<?, ?>) oldValue).isMutable()) {
|
||||
Object newValue = extSchema.newInstance();
|
||||
extSchema.mergeFrom(newValue, oldValue);
|
||||
extensions.setField(extension.descriptor, newValue);
|
||||
oldValue = newValue;
|
||||
}
|
||||
reader.mergeMessageField(oldValue, extSchema, extensionRegistry);
|
||||
return unknownFields;
|
||||
}
|
||||
}
|
||||
value =
|
||||
reader.readMessage(
|
||||
extension.getMessageDefaultInstance().getClass(), extensionRegistry);
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
throw new IllegalStateException("Shouldn't reach here.");
|
||||
}
|
||||
}
|
||||
if (extension.isRepeated()) {
|
||||
extensions.addRepeatedField(extension.descriptor, value);
|
||||
} else {
|
||||
switch (extension.getLiteType()) {
|
||||
case MESSAGE:
|
||||
case GROUP:
|
||||
// TODO(b/249368670): this shouldn't be reachable, clean this up
|
||||
Object oldValue = extensions.getField(extension.descriptor);
|
||||
if (oldValue != null) {
|
||||
value = Internal.mergeMessage(oldValue, value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
extensions.setField(extension.descriptor, value);
|
||||
}
|
||||
}
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
int extensionNumber(Map.Entry<?, ?> extension) {
|
||||
GeneratedMessageLite.ExtensionDescriptor descriptor =
|
||||
(GeneratedMessageLite.ExtensionDescriptor) extension.getKey();
|
||||
return descriptor.getNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
void serializeExtension(Writer writer, Map.Entry<?, ?> extension) throws IOException {
|
||||
GeneratedMessageLite.ExtensionDescriptor descriptor =
|
||||
(GeneratedMessageLite.ExtensionDescriptor) extension.getKey();
|
||||
if (descriptor.isRepeated()) {
|
||||
switch (descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
SchemaUtil.writeDoubleList(
|
||||
descriptor.getNumber(),
|
||||
(List<Double>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FLOAT:
|
||||
SchemaUtil.writeFloatList(
|
||||
descriptor.getNumber(),
|
||||
(List<Float>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case INT64:
|
||||
SchemaUtil.writeInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case UINT64:
|
||||
SchemaUtil.writeUInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case INT32:
|
||||
SchemaUtil.writeInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FIXED64:
|
||||
SchemaUtil.writeFixed64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case FIXED32:
|
||||
SchemaUtil.writeFixed32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case BOOL:
|
||||
SchemaUtil.writeBoolList(
|
||||
descriptor.getNumber(),
|
||||
(List<Boolean>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case BYTES:
|
||||
SchemaUtil.writeBytesList(
|
||||
descriptor.getNumber(), (List<ByteString>) extension.getValue(), writer);
|
||||
break;
|
||||
case UINT32:
|
||||
SchemaUtil.writeUInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SFIXED32:
|
||||
SchemaUtil.writeSFixed32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SFIXED64:
|
||||
SchemaUtil.writeSFixed64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SINT32:
|
||||
SchemaUtil.writeSInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case SINT64:
|
||||
SchemaUtil.writeSInt64List(
|
||||
descriptor.getNumber(),
|
||||
(List<Long>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case ENUM:
|
||||
SchemaUtil.writeInt32List(
|
||||
descriptor.getNumber(),
|
||||
(List<Integer>) extension.getValue(),
|
||||
writer,
|
||||
descriptor.isPacked());
|
||||
break;
|
||||
case STRING:
|
||||
SchemaUtil.writeStringList(
|
||||
descriptor.getNumber(), (List<String>) extension.getValue(), writer);
|
||||
break;
|
||||
case GROUP:
|
||||
{
|
||||
List<?> data = (List<?>) extension.getValue();
|
||||
if (data != null && !data.isEmpty()) {
|
||||
SchemaUtil.writeGroupList(
|
||||
descriptor.getNumber(),
|
||||
(List<?>) extension.getValue(),
|
||||
writer,
|
||||
Protobuf.getInstance().schemaFor(data.get(0).getClass()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
{
|
||||
List<?> data = (List<?>) extension.getValue();
|
||||
if (data != null && !data.isEmpty()) {
|
||||
SchemaUtil.writeMessageList(
|
||||
descriptor.getNumber(),
|
||||
(List<?>) extension.getValue(),
|
||||
writer,
|
||||
Protobuf.getInstance().schemaFor(data.get(0).getClass()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (descriptor.getLiteType()) {
|
||||
case DOUBLE:
|
||||
writer.writeDouble(descriptor.getNumber(), (Double) extension.getValue());
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.writeFloat(descriptor.getNumber(), (Float) extension.getValue());
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case UINT64:
|
||||
writer.writeUInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case INT32:
|
||||
writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case FIXED64:
|
||||
writer.writeFixed64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case FIXED32:
|
||||
writer.writeFixed32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case BOOL:
|
||||
writer.writeBool(descriptor.getNumber(), (Boolean) extension.getValue());
|
||||
break;
|
||||
case BYTES:
|
||||
writer.writeBytes(descriptor.getNumber(), (ByteString) extension.getValue());
|
||||
break;
|
||||
case UINT32:
|
||||
writer.writeUInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SFIXED32:
|
||||
writer.writeSFixed32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SFIXED64:
|
||||
writer.writeSFixed64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case SINT32:
|
||||
writer.writeSInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case SINT64:
|
||||
writer.writeSInt64(descriptor.getNumber(), (Long) extension.getValue());
|
||||
break;
|
||||
case ENUM:
|
||||
writer.writeInt32(descriptor.getNumber(), (Integer) extension.getValue());
|
||||
break;
|
||||
case STRING:
|
||||
writer.writeString(descriptor.getNumber(), (String) extension.getValue());
|
||||
break;
|
||||
case GROUP:
|
||||
writer.writeGroup(
|
||||
descriptor.getNumber(),
|
||||
extension.getValue(),
|
||||
Protobuf.getInstance().schemaFor(extension.getValue().getClass()));
|
||||
break;
|
||||
case MESSAGE:
|
||||
writer.writeMessage(
|
||||
descriptor.getNumber(),
|
||||
extension.getValue(),
|
||||
Protobuf.getInstance().schemaFor(extension.getValue().getClass()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object findExtensionByNumber(
|
||||
ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number) {
|
||||
return extensionRegistry.findLiteExtensionByNumber(defaultInstance, number);
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseLengthPrefixedMessageSetItem(
|
||||
Reader reader,
|
||||
Object extensionObject,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<ExtensionDescriptor> extensions)
|
||||
throws IOException {
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?> extension =
|
||||
(GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject;
|
||||
Object value =
|
||||
reader.readMessage(extension.getMessageDefaultInstance().getClass(), extensionRegistry);
|
||||
extensions.setField(extension.descriptor, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseMessageSetItem(
|
||||
ByteString data,
|
||||
Object extensionObject,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
FieldSet<ExtensionDescriptor> extensions)
|
||||
throws IOException {
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?> extension =
|
||||
(GeneratedMessageLite.GeneratedExtension<?, ?>) extensionObject;
|
||||
|
||||
MessageLite.Builder builder = extension.getMessageDefaultInstance().newBuilderForType();
|
||||
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
|
||||
builder.mergeFrom(input, extensionRegistry);
|
||||
extensions.setField(extension.descriptor, builder.buildPartial());
|
||||
input.checkLastTagWas(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
@CheckReturnValue
|
||||
final class ExtensionSchemas {
|
||||
private static final ExtensionSchema<?> LITE_SCHEMA = new ExtensionSchemaLite();
|
||||
private static final ExtensionSchema<?> FULL_SCHEMA = loadSchemaForFullRuntime();
|
||||
|
||||
private static ExtensionSchema<?> loadSchemaForFullRuntime() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.google.protobuf.ExtensionSchemaFull");
|
||||
return (ExtensionSchema) clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static ExtensionSchema<?> lite() {
|
||||
return LITE_SCHEMA;
|
||||
}
|
||||
|
||||
static ExtensionSchema<?> full() {
|
||||
if (FULL_SCHEMA == null) {
|
||||
throw new IllegalStateException("Protobuf runtime is not correctly loaded.");
|
||||
}
|
||||
return FULL_SCHEMA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.EnumVerifier;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/** Information for a single field in a protobuf message class. */
|
||||
@CheckReturnValue
|
||||
@ExperimentalApi
|
||||
final class FieldInfo implements Comparable<FieldInfo> {
|
||||
private final Field field;
|
||||
private final FieldType type;
|
||||
private final Class<?> messageClass; // The message type for repeated message fields.
|
||||
private final int fieldNumber;
|
||||
private final Field presenceField;
|
||||
private final int presenceMask;
|
||||
private final boolean required;
|
||||
private final boolean enforceUtf8;
|
||||
private final OneofInfo oneof;
|
||||
private final Field cachedSizeField;
|
||||
/**
|
||||
* The actual type stored in the oneof value for this field. Since the oneof value is an {@link
|
||||
* Object}, primitives will store their boxed type. Only valid in conjunction with {@link #oneof}
|
||||
* (both must be either null or non-null.
|
||||
*/
|
||||
private final Class<?> oneofStoredType;
|
||||
|
||||
// TODO(liujisi): make map default entry lazy?
|
||||
private final Object mapDefaultEntry;
|
||||
|
||||
private final EnumVerifier enumVerifier;
|
||||
|
||||
/** Constructs a new descriptor for a field. */
|
||||
public static FieldInfo forField(
|
||||
Field field, int fieldNumber, FieldType fieldType, boolean enforceUtf8) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
if (fieldType == FieldType.MESSAGE_LIST || fieldType == FieldType.GROUP_LIST) {
|
||||
throw new IllegalStateException("Shouldn't be called for repeated message fields.");
|
||||
}
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
enforceUtf8,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
/* enumVerifier= */ null,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
/** Constructs a new descriptor for a packed field. */
|
||||
public static FieldInfo forPackedField(
|
||||
Field field, int fieldNumber, FieldType fieldType, Field cachedSizeField) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
if (fieldType == FieldType.MESSAGE_LIST || fieldType == FieldType.GROUP_LIST) {
|
||||
throw new IllegalStateException("Shouldn't be called for repeated message fields.");
|
||||
}
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
/* enforceUtf8= */ false,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
/* enumVerifier= */ null,
|
||||
cachedSizeField);
|
||||
}
|
||||
|
||||
/** Constructs a new descriptor for a repeated message field. */
|
||||
public static FieldInfo forRepeatedMessageField(
|
||||
Field field, int fieldNumber, FieldType fieldType, Class<?> messageClass) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
checkNotNull(messageClass, "messageClass");
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
messageClass,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
/* enforceUtf8= */ false,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
/* enumVerifier= */ null,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
public static FieldInfo forFieldWithEnumVerifier(
|
||||
Field field, int fieldNumber, FieldType fieldType, EnumVerifier enumVerifier) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
/* enforceUtf8= */ false,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
enumVerifier,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
public static FieldInfo forPackedFieldWithEnumVerifier(
|
||||
Field field,
|
||||
int fieldNumber,
|
||||
FieldType fieldType,
|
||||
EnumVerifier enumVerifier,
|
||||
Field cachedSizeField) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
/* enforceUtf8= */ false,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
enumVerifier,
|
||||
cachedSizeField);
|
||||
}
|
||||
|
||||
/** Constructor for a proto2 optional field. */
|
||||
public static FieldInfo forProto2OptionalField(
|
||||
Field field,
|
||||
int fieldNumber,
|
||||
FieldType fieldType,
|
||||
Field presenceField,
|
||||
int presenceMask,
|
||||
boolean enforceUtf8,
|
||||
EnumVerifier enumVerifier) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
checkNotNull(presenceField, "presenceField");
|
||||
if (presenceField != null && !isExactlyOneBitSet(presenceMask)) {
|
||||
throw new IllegalArgumentException(
|
||||
"presenceMask must have exactly one bit set: " + presenceMask);
|
||||
}
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
presenceField,
|
||||
presenceMask,
|
||||
/* required= */ false,
|
||||
enforceUtf8,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
enumVerifier,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a field that is part of a oneof.
|
||||
*
|
||||
* @param fieldNumber the unique field number for this field within the message.
|
||||
* @param fieldType the type of the field (must be non-null).
|
||||
* @param oneof the oneof for which this field is associated (must be non-null).
|
||||
* @param oneofStoredType the actual type stored in the oneof value for this field. Since the
|
||||
* oneof value is an {@link Object}, primitives will store their boxed type. Must be non-null.
|
||||
* @param enforceUtf8 Only used for string fields. If {@code true}, will enforce UTF-8 on a string
|
||||
* field.
|
||||
* @return the {@link FieldInfo} describing this field.
|
||||
*/
|
||||
public static FieldInfo forOneofMemberField(
|
||||
int fieldNumber,
|
||||
FieldType fieldType,
|
||||
OneofInfo oneof,
|
||||
Class<?> oneofStoredType,
|
||||
boolean enforceUtf8,
|
||||
EnumVerifier enumVerifier) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
checkNotNull(oneof, "oneof");
|
||||
checkNotNull(oneofStoredType, "oneofStoredType");
|
||||
if (!fieldType.isScalar()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Oneof is only supported for scalar fields. Field "
|
||||
+ fieldNumber
|
||||
+ " is of type "
|
||||
+ fieldType);
|
||||
}
|
||||
return new FieldInfo(
|
||||
/* field= */ null,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
enforceUtf8,
|
||||
oneof,
|
||||
oneofStoredType,
|
||||
/* mapDefaultEntry= */ null,
|
||||
enumVerifier,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
private static void checkFieldNumber(int fieldNumber) {
|
||||
if (fieldNumber <= 0) {
|
||||
throw new IllegalArgumentException("fieldNumber must be positive: " + fieldNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructor for a proto2 required field. */
|
||||
public static FieldInfo forProto2RequiredField(
|
||||
Field field,
|
||||
int fieldNumber,
|
||||
FieldType fieldType,
|
||||
Field presenceField,
|
||||
int presenceMask,
|
||||
boolean enforceUtf8,
|
||||
EnumVerifier enumVerifier) {
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
checkNotNull(fieldType, "fieldType");
|
||||
checkNotNull(presenceField, "presenceField");
|
||||
if (presenceField != null && !isExactlyOneBitSet(presenceMask)) {
|
||||
throw new IllegalArgumentException(
|
||||
"presenceMask must have exactly one bit set: " + presenceMask);
|
||||
}
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
fieldType,
|
||||
/* messageClass= */ null,
|
||||
presenceField,
|
||||
presenceMask,
|
||||
/* required= */ true,
|
||||
enforceUtf8,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
/* mapDefaultEntry= */ null,
|
||||
/* enumVerifier= */ enumVerifier,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
public static FieldInfo forMapField(
|
||||
Field field, int fieldNumber, Object mapDefaultEntry, EnumVerifier enumVerifier) {
|
||||
checkNotNull(mapDefaultEntry, "mapDefaultEntry");
|
||||
checkFieldNumber(fieldNumber);
|
||||
checkNotNull(field, "field");
|
||||
return new FieldInfo(
|
||||
field,
|
||||
fieldNumber,
|
||||
FieldType.MAP,
|
||||
/* messageClass= */ null,
|
||||
/* presenceField= */ null,
|
||||
/* presenceMask= */ 0,
|
||||
/* required= */ false,
|
||||
/* enforceUtf8= */ true,
|
||||
/* oneof= */ null,
|
||||
/* oneofStoredType= */ null,
|
||||
mapDefaultEntry,
|
||||
enumVerifier,
|
||||
/* cachedSizeField= */ null);
|
||||
}
|
||||
|
||||
private FieldInfo(
|
||||
Field field,
|
||||
int fieldNumber,
|
||||
FieldType type,
|
||||
Class<?> messageClass,
|
||||
Field presenceField,
|
||||
int presenceMask,
|
||||
boolean required,
|
||||
boolean enforceUtf8,
|
||||
OneofInfo oneof,
|
||||
Class<?> oneofStoredType,
|
||||
Object mapDefaultEntry,
|
||||
EnumVerifier enumVerifier,
|
||||
Field cachedSizeField) {
|
||||
this.field = field;
|
||||
this.type = type;
|
||||
this.messageClass = messageClass;
|
||||
this.fieldNumber = fieldNumber;
|
||||
this.presenceField = presenceField;
|
||||
this.presenceMask = presenceMask;
|
||||
this.required = required;
|
||||
this.enforceUtf8 = enforceUtf8;
|
||||
this.oneof = oneof;
|
||||
this.oneofStoredType = oneofStoredType;
|
||||
this.mapDefaultEntry = mapDefaultEntry;
|
||||
this.enumVerifier = enumVerifier;
|
||||
this.cachedSizeField = cachedSizeField;
|
||||
}
|
||||
|
||||
/** Gets the field number for the field. */
|
||||
public int getFieldNumber() {
|
||||
return fieldNumber;
|
||||
}
|
||||
|
||||
/** Gets the subject {@link Field} of this descriptor. */
|
||||
public Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/** Gets the type information for the field. */
|
||||
public FieldType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/** Gets the oneof for which this field is a member, or {@code null} if not part of a oneof. */
|
||||
public OneofInfo getOneof() {
|
||||
return oneof;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the actual type stored in the oneof value by this field. Since the oneof value is an
|
||||
* {@link Object}, primitives will store their boxed type. For non-oneof fields, this will always
|
||||
* be {@code null}.
|
||||
*/
|
||||
public Class<?> getOneofStoredType() {
|
||||
return oneofStoredType;
|
||||
}
|
||||
|
||||
/** Gets the {@code EnumVerifier} if the field is an enum field. */
|
||||
public EnumVerifier getEnumVerifier() {
|
||||
return enumVerifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FieldInfo o) {
|
||||
return fieldNumber - o.fieldNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* For repeated message fields, returns the message type of the field. For other fields, returns
|
||||
* {@code null}.
|
||||
*/
|
||||
public Class<?> getListElementType() {
|
||||
return messageClass;
|
||||
}
|
||||
|
||||
/** Gets the presence bit field. Only valid for unary fields. For lists, returns {@code null}. */
|
||||
public Field getPresenceField() {
|
||||
return presenceField;
|
||||
}
|
||||
|
||||
public Object getMapDefaultEntry() {
|
||||
return mapDefaultEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link #getPresenceField()} is non-{@code null}, returns the mask used to identify the
|
||||
* presence bit for this field in the message.
|
||||
*/
|
||||
public int getPresenceMask() {
|
||||
return presenceMask;
|
||||
}
|
||||
|
||||
/** Whether this is a required field. */
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a UTF-8 should be enforced on string fields. Only applies to strings and string lists.
|
||||
*/
|
||||
public boolean isEnforceUtf8() {
|
||||
return enforceUtf8;
|
||||
}
|
||||
|
||||
public Field getCachedSizeField() {
|
||||
return cachedSizeField;
|
||||
}
|
||||
|
||||
/**
|
||||
* For singular or repeated message fields, returns the message type. For other fields, returns
|
||||
* {@code null}.
|
||||
*/
|
||||
public Class<?> getMessageFieldClass() {
|
||||
switch (type) {
|
||||
case MESSAGE:
|
||||
case GROUP:
|
||||
return field != null ? field.getType() : oneofStoredType;
|
||||
case MESSAGE_LIST:
|
||||
case GROUP_LIST:
|
||||
return messageClass;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/** A builder for {@link FieldInfo} instances. */
|
||||
public static final class Builder {
|
||||
private Field field;
|
||||
private FieldType type;
|
||||
private int fieldNumber;
|
||||
private Field presenceField;
|
||||
private int presenceMask;
|
||||
private boolean required;
|
||||
private boolean enforceUtf8;
|
||||
private OneofInfo oneof;
|
||||
private Class<?> oneofStoredType;
|
||||
private Object mapDefaultEntry;
|
||||
private EnumVerifier enumVerifier;
|
||||
private Field cachedSizeField;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
/**
|
||||
* Specifies the actual field on the message represented by this field. This should not be
|
||||
* called for oneof member fields.
|
||||
*/
|
||||
public Builder withField(Field field) {
|
||||
if (oneof != null) {
|
||||
throw new IllegalStateException("Cannot set field when building a oneof.");
|
||||
}
|
||||
this.field = field;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies the type of this field. */
|
||||
public Builder withType(FieldType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies the unique field number for this field within the message. */
|
||||
public Builder withFieldNumber(int fieldNumber) {
|
||||
this.fieldNumber = fieldNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies proto2 presence information. This should not be called for oneof fields. */
|
||||
public Builder withPresence(Field presenceField, int presenceMask) {
|
||||
this.presenceField = checkNotNull(presenceField, "presenceField");
|
||||
this.presenceMask = presenceMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the information for building a oneof member field. This is incompatible with {@link
|
||||
* #withField(Field)} and {@link #withPresence(Field, int)}.
|
||||
*
|
||||
* @param oneof the oneof for which this field is associated.
|
||||
* @param oneofStoredType the actual type stored in the oneof value for this field. Since the
|
||||
* oneof value is an {@link Object}, primitives will store their boxed type.
|
||||
*/
|
||||
public Builder withOneof(OneofInfo oneof, Class<?> oneofStoredType) {
|
||||
if (field != null || presenceField != null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot set oneof when field or presenceField have been provided");
|
||||
}
|
||||
this.oneof = oneof;
|
||||
this.oneofStoredType = oneofStoredType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withRequired(boolean required) {
|
||||
this.required = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withMapDefaultEntry(Object mapDefaultEntry) {
|
||||
this.mapDefaultEntry = mapDefaultEntry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withEnforceUtf8(boolean enforceUtf8) {
|
||||
this.enforceUtf8 = enforceUtf8;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withEnumVerifier(EnumVerifier enumVerifier) {
|
||||
this.enumVerifier = enumVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCachedSizeField(Field cachedSizeField) {
|
||||
this.cachedSizeField = cachedSizeField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldInfo build() {
|
||||
if (oneof != null) {
|
||||
return forOneofMemberField(
|
||||
fieldNumber, type, oneof, oneofStoredType, enforceUtf8, enumVerifier);
|
||||
}
|
||||
if (mapDefaultEntry != null) {
|
||||
return forMapField(field, fieldNumber, mapDefaultEntry, enumVerifier);
|
||||
}
|
||||
if (presenceField != null) {
|
||||
if (required) {
|
||||
return forProto2RequiredField(
|
||||
field, fieldNumber, type, presenceField, presenceMask, enforceUtf8, enumVerifier);
|
||||
} else {
|
||||
return forProto2OptionalField(
|
||||
field, fieldNumber, type, presenceField, presenceMask, enforceUtf8, enumVerifier);
|
||||
}
|
||||
}
|
||||
if (enumVerifier != null) {
|
||||
if (cachedSizeField == null) {
|
||||
return forFieldWithEnumVerifier(field, fieldNumber, type, enumVerifier);
|
||||
} else {
|
||||
return forPackedFieldWithEnumVerifier(
|
||||
field, fieldNumber, type, enumVerifier, cachedSizeField);
|
||||
}
|
||||
} else {
|
||||
if (cachedSizeField == null) {
|
||||
return forField(field, fieldNumber, type, enforceUtf8);
|
||||
} else {
|
||||
return forPackedField(field, fieldNumber, type, cachedSizeField);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExactlyOneBitSet(int value) {
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,344 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.List;
|
||||
|
||||
/** Enumeration identifying all relevant type information for a protobuf field. */
|
||||
@ExperimentalApi
|
||||
public enum FieldType {
|
||||
DOUBLE(0, Collection.SCALAR, JavaType.DOUBLE),
|
||||
FLOAT(1, Collection.SCALAR, JavaType.FLOAT),
|
||||
INT64(2, Collection.SCALAR, JavaType.LONG),
|
||||
UINT64(3, Collection.SCALAR, JavaType.LONG),
|
||||
INT32(4, Collection.SCALAR, JavaType.INT),
|
||||
FIXED64(5, Collection.SCALAR, JavaType.LONG),
|
||||
FIXED32(6, Collection.SCALAR, JavaType.INT),
|
||||
BOOL(7, Collection.SCALAR, JavaType.BOOLEAN),
|
||||
STRING(8, Collection.SCALAR, JavaType.STRING),
|
||||
MESSAGE(9, Collection.SCALAR, JavaType.MESSAGE),
|
||||
BYTES(10, Collection.SCALAR, JavaType.BYTE_STRING),
|
||||
UINT32(11, Collection.SCALAR, JavaType.INT),
|
||||
ENUM(12, Collection.SCALAR, JavaType.ENUM),
|
||||
SFIXED32(13, Collection.SCALAR, JavaType.INT),
|
||||
SFIXED64(14, Collection.SCALAR, JavaType.LONG),
|
||||
SINT32(15, Collection.SCALAR, JavaType.INT),
|
||||
SINT64(16, Collection.SCALAR, JavaType.LONG),
|
||||
GROUP(17, Collection.SCALAR, JavaType.MESSAGE),
|
||||
DOUBLE_LIST(18, Collection.VECTOR, JavaType.DOUBLE),
|
||||
FLOAT_LIST(19, Collection.VECTOR, JavaType.FLOAT),
|
||||
INT64_LIST(20, Collection.VECTOR, JavaType.LONG),
|
||||
UINT64_LIST(21, Collection.VECTOR, JavaType.LONG),
|
||||
INT32_LIST(22, Collection.VECTOR, JavaType.INT),
|
||||
FIXED64_LIST(23, Collection.VECTOR, JavaType.LONG),
|
||||
FIXED32_LIST(24, Collection.VECTOR, JavaType.INT),
|
||||
BOOL_LIST(25, Collection.VECTOR, JavaType.BOOLEAN),
|
||||
STRING_LIST(26, Collection.VECTOR, JavaType.STRING),
|
||||
MESSAGE_LIST(27, Collection.VECTOR, JavaType.MESSAGE),
|
||||
BYTES_LIST(28, Collection.VECTOR, JavaType.BYTE_STRING),
|
||||
UINT32_LIST(29, Collection.VECTOR, JavaType.INT),
|
||||
ENUM_LIST(30, Collection.VECTOR, JavaType.ENUM),
|
||||
SFIXED32_LIST(31, Collection.VECTOR, JavaType.INT),
|
||||
SFIXED64_LIST(32, Collection.VECTOR, JavaType.LONG),
|
||||
SINT32_LIST(33, Collection.VECTOR, JavaType.INT),
|
||||
SINT64_LIST(34, Collection.VECTOR, JavaType.LONG),
|
||||
DOUBLE_LIST_PACKED(35, Collection.PACKED_VECTOR, JavaType.DOUBLE),
|
||||
FLOAT_LIST_PACKED(36, Collection.PACKED_VECTOR, JavaType.FLOAT),
|
||||
INT64_LIST_PACKED(37, Collection.PACKED_VECTOR, JavaType.LONG),
|
||||
UINT64_LIST_PACKED(38, Collection.PACKED_VECTOR, JavaType.LONG),
|
||||
INT32_LIST_PACKED(39, Collection.PACKED_VECTOR, JavaType.INT),
|
||||
FIXED64_LIST_PACKED(40, Collection.PACKED_VECTOR, JavaType.LONG),
|
||||
FIXED32_LIST_PACKED(41, Collection.PACKED_VECTOR, JavaType.INT),
|
||||
BOOL_LIST_PACKED(42, Collection.PACKED_VECTOR, JavaType.BOOLEAN),
|
||||
UINT32_LIST_PACKED(43, Collection.PACKED_VECTOR, JavaType.INT),
|
||||
ENUM_LIST_PACKED(44, Collection.PACKED_VECTOR, JavaType.ENUM),
|
||||
SFIXED32_LIST_PACKED(45, Collection.PACKED_VECTOR, JavaType.INT),
|
||||
SFIXED64_LIST_PACKED(46, Collection.PACKED_VECTOR, JavaType.LONG),
|
||||
SINT32_LIST_PACKED(47, Collection.PACKED_VECTOR, JavaType.INT),
|
||||
SINT64_LIST_PACKED(48, Collection.PACKED_VECTOR, JavaType.LONG),
|
||||
GROUP_LIST(49, Collection.VECTOR, JavaType.MESSAGE),
|
||||
MAP(50, Collection.MAP, JavaType.VOID);
|
||||
|
||||
private final JavaType javaType;
|
||||
private final int id;
|
||||
private final Collection collection;
|
||||
private final Class<?> elementType;
|
||||
private final boolean primitiveScalar;
|
||||
|
||||
FieldType(int id, Collection collection, JavaType javaType) {
|
||||
this.id = id;
|
||||
this.collection = collection;
|
||||
this.javaType = javaType;
|
||||
|
||||
switch (collection) {
|
||||
case MAP:
|
||||
elementType = javaType.getBoxedType();
|
||||
break;
|
||||
case VECTOR:
|
||||
elementType = javaType.getBoxedType();
|
||||
break;
|
||||
case SCALAR:
|
||||
default:
|
||||
elementType = null;
|
||||
break;
|
||||
}
|
||||
|
||||
boolean primitiveScalar = false;
|
||||
if (collection == Collection.SCALAR) {
|
||||
switch (javaType) {
|
||||
case BYTE_STRING:
|
||||
case MESSAGE:
|
||||
case STRING:
|
||||
break;
|
||||
default:
|
||||
primitiveScalar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.primitiveScalar = primitiveScalar;
|
||||
}
|
||||
|
||||
/** A reliable unique identifier for this type. */
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link JavaType} for this field. For lists, this identifies the type of the elements
|
||||
* contained within the list.
|
||||
*/
|
||||
public JavaType getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
/** Indicates whether a list field should be represented on the wire in packed form. */
|
||||
public boolean isPacked() {
|
||||
return Collection.PACKED_VECTOR.equals(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this field type represents a primitive scalar value. If this is {@code true},
|
||||
* then {@link #isScalar()} will also be {@code true}.
|
||||
*/
|
||||
public boolean isPrimitiveScalar() {
|
||||
return primitiveScalar;
|
||||
}
|
||||
|
||||
/** Indicates whether this field type represents a scalar value. */
|
||||
public boolean isScalar() {
|
||||
return collection == Collection.SCALAR;
|
||||
}
|
||||
|
||||
/** Indicates whether this field represents a list of values. */
|
||||
public boolean isList() {
|
||||
return collection.isList();
|
||||
}
|
||||
|
||||
/** Indicates whether this field represents a map. */
|
||||
public boolean isMap() {
|
||||
return collection == Collection.MAP;
|
||||
}
|
||||
|
||||
/** Indicates whether or not this {@link FieldType} can be applied to the given {@link Field}. */
|
||||
public boolean isValidForField(Field field) {
|
||||
if (Collection.VECTOR.equals(collection)) {
|
||||
return isValidForList(field);
|
||||
} else {
|
||||
return javaType.getType().isAssignableFrom(field.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidForList(Field field) {
|
||||
Class<?> clazz = field.getType();
|
||||
if (!javaType.getType().isAssignableFrom(clazz)) {
|
||||
// The field isn't a List type.
|
||||
return false;
|
||||
}
|
||||
Type[] types = EMPTY_TYPES;
|
||||
Type genericType = field.getGenericType();
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
|
||||
}
|
||||
Type listParameter = getListParameter(clazz, types);
|
||||
if (!(listParameter instanceof Class)) {
|
||||
// It's a wildcard, we should allow anything in the list.
|
||||
return true;
|
||||
}
|
||||
return elementType.isAssignableFrom((Class<?>) listParameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the appropriate {@link FieldType} by it's identifier.
|
||||
*
|
||||
* @return the {@link FieldType} or {@code null} if not found.
|
||||
*/
|
||||
public static FieldType forId(int id) {
|
||||
if (id < 0 || id >= VALUES.length) {
|
||||
return null;
|
||||
}
|
||||
return VALUES[id];
|
||||
}
|
||||
|
||||
private static final FieldType[] VALUES;
|
||||
private static final Type[] EMPTY_TYPES = new Type[0];
|
||||
|
||||
static {
|
||||
FieldType[] values = values();
|
||||
VALUES = new FieldType[values.length];
|
||||
for (FieldType type : values) {
|
||||
VALUES[type.id] = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a class, finds a generic super class or interface that extends {@link List}.
|
||||
*
|
||||
* @return the generic super class/interface, or {@code null} if not found.
|
||||
*/
|
||||
private static Type getGenericSuperList(Class<?> clazz) {
|
||||
// First look at interfaces.
|
||||
Type[] genericInterfaces = clazz.getGenericInterfaces();
|
||||
for (Type genericInterface : genericInterfaces) {
|
||||
if (genericInterface instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
|
||||
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
|
||||
if (List.class.isAssignableFrom(rawType)) {
|
||||
return genericInterface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try the subclass
|
||||
Type type = clazz.getGenericSuperclass();
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
|
||||
if (List.class.isAssignableFrom(rawType)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
// No super class/interface extends List.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the inheritance hierarchy for the given class and finds the generic type parameter for
|
||||
* {@link List}.
|
||||
*
|
||||
* @param clazz the class to begin the search.
|
||||
* @param realTypes the array of actual type parameters for {@code clazz}. These will be used to
|
||||
* substitute generic parameters up the inheritance hierarchy. If {@code clazz} does not have
|
||||
* any generic parameters, this list should be empty.
|
||||
* @return the {@link List} parameter.
|
||||
*/
|
||||
private static Type getListParameter(Class<?> clazz, Type[] realTypes) {
|
||||
top:
|
||||
while (clazz != List.class) {
|
||||
// First look at generic subclass and interfaces.
|
||||
Type genericType = getGenericSuperList(clazz);
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
// Replace any generic parameters with the real values.
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericType;
|
||||
Type[] superArgs = parameterizedType.getActualTypeArguments();
|
||||
for (int i = 0; i < superArgs.length; ++i) {
|
||||
Type superArg = superArgs[i];
|
||||
if (superArg instanceof TypeVariable) {
|
||||
// Get the type variables for this class so that we can match them to the variables
|
||||
// used on the super class.
|
||||
TypeVariable<?>[] clazzParams = clazz.getTypeParameters();
|
||||
if (realTypes.length != clazzParams.length) {
|
||||
throw new RuntimeException("Type array mismatch");
|
||||
}
|
||||
|
||||
// Replace the variable parameter with the real type.
|
||||
boolean foundReplacement = false;
|
||||
for (int j = 0; j < clazzParams.length; ++j) {
|
||||
if (superArg == clazzParams[j]) {
|
||||
Type realType = realTypes[j];
|
||||
superArgs[i] = realType;
|
||||
foundReplacement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundReplacement) {
|
||||
throw new RuntimeException("Unable to find replacement for " + superArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> parent = (Class<?>) parameterizedType.getRawType();
|
||||
|
||||
realTypes = superArgs;
|
||||
clazz = parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// None of the parameterized types inherit List. Just continue up the inheritance hierarchy
|
||||
// toward the List interface until we can identify the parameters.
|
||||
realTypes = EMPTY_TYPES;
|
||||
for (Class<?> iface : clazz.getInterfaces()) {
|
||||
if (List.class.isAssignableFrom(iface)) {
|
||||
clazz = iface;
|
||||
continue top;
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
|
||||
if (realTypes.length != 1) {
|
||||
throw new RuntimeException("Unable to identify parameter type for List<T>");
|
||||
}
|
||||
return realTypes[0];
|
||||
}
|
||||
|
||||
enum Collection {
|
||||
SCALAR(false),
|
||||
VECTOR(true),
|
||||
PACKED_VECTOR(true),
|
||||
MAP(false);
|
||||
|
||||
private final boolean isList;
|
||||
|
||||
Collection(boolean isList) {
|
||||
this.isList = isList;
|
||||
}
|
||||
|
||||
/** @return the isList */
|
||||
public boolean isList() {
|
||||
return isList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.FloatList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link FloatList} on top of a primitive array.
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class FloatArrayList extends AbstractProtobufList<Float>
|
||||
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final FloatArrayList EMPTY_LIST = new FloatArrayList(new float[0], 0);
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
public static FloatArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/** The backing store for the list. */
|
||||
private float[] array;
|
||||
|
||||
/**
|
||||
* The size of the list distinct from the length of the array. That is, it is the number of
|
||||
* elements set in the list.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** 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}.
|
||||
*/
|
||||
private FloatArrayList(float[] other, int size) {
|
||||
array = other;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
ensureIsMutable();
|
||||
if (toIndex < fromIndex) {
|
||||
throw new IndexOutOfBoundsException("toIndex < fromIndex");
|
||||
}
|
||||
|
||||
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof FloatArrayList)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
FloatArrayList other = (FloatArrayList) o;
|
||||
if (size != other.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final float[] arr = other.array;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (Float.floatToIntBits(array[i]) != Float.floatToIntBits(arr[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
result = (31 * result) + Float.floatToIntBits(array[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new FloatArrayList(Arrays.copyOf(array, capacity), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(int index) {
|
||||
return getFloat(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
if (!(element instanceof Float)) {
|
||||
return -1;
|
||||
}
|
||||
float unboxedElement = (Float) element;
|
||||
int numElems = size();
|
||||
for (int i = 0; i < numElems; i++) {
|
||||
if (array[i] == unboxedElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
return indexOf(element) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float set(int index, Float element) {
|
||||
return setFloat(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float setFloat(int index, float element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
float previousValue = array[index];
|
||||
array[index] = element;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Float element) {
|
||||
addFloat(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Float element) {
|
||||
addFloat(index, element);
|
||||
}
|
||||
|
||||
/** Like {@link #add(Float)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addFloat(float element) {
|
||||
ensureIsMutable();
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
float[] newArray = new float[length];
|
||||
|
||||
System.arraycopy(array, 0, newArray, 0, size);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = 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) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
float[] newArray = new float[length];
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Float> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another FloatArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof FloatArrayList)) {
|
||||
return super.addAll(collection);
|
||||
}
|
||||
|
||||
FloatArrayList list = (FloatArrayList) collection;
|
||||
if (list.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int overflow = Integer.MAX_VALUE - size;
|
||||
if (overflow < list.size) {
|
||||
// We can't actually represent a list this large.
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
int newSize = size + list.size;
|
||||
if (newSize > array.length) {
|
||||
array = Arrays.copyOf(array, newSize);
|
||||
}
|
||||
|
||||
System.arraycopy(list.array, 0, array, size, list.size);
|
||||
size = newSize;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
float value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
|
||||
* {@link IndexOutOfBoundsException} if it is not.
|
||||
*
|
||||
* @param index the index to verify is in range
|
||||
*/
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** A factory for message info that is generated into the message itself. */
|
||||
@ExperimentalApi
|
||||
class GeneratedMessageInfoFactory implements MessageInfoFactory {
|
||||
|
||||
private static final GeneratedMessageInfoFactory instance = new GeneratedMessageInfoFactory();
|
||||
|
||||
// Disallow construction - it's a singleton.
|
||||
private GeneratedMessageInfoFactory() {}
|
||||
|
||||
public static GeneratedMessageInfoFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Class<?> messageType) {
|
||||
return GeneratedMessageLite.class.isAssignableFrom(messageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo messageInfoFor(Class<?> messageType) {
|
||||
if (!GeneratedMessageLite.class.isAssignableFrom(messageType)) {
|
||||
throw new IllegalArgumentException("Unsupported message type: " + messageType.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
return (MessageInfo) GeneratedMessageLite.getDefaultInstance(
|
||||
messageType.asSubclass(GeneratedMessageLite.class))
|
||||
.buildMessageInfo();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to get message info for " + messageType.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that callers of this API should be inlined. That is, this API is trivially expressible
|
||||
* in terms of another API, for example a method that just calls another method.
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD, CONSTRUCTOR})
|
||||
@interface InlineMe {
|
||||
/**
|
||||
* What the caller should be replaced with. Local parameter names can be used in the replacement
|
||||
* string. If you are invoking an instance method or constructor, you must include the implicit
|
||||
* {@code this} in the replacement body. If you are invoking a static method, you must include the
|
||||
* implicit {@code ClassName} in the replacement body.
|
||||
*/
|
||||
String replacement();
|
||||
|
||||
/** The new imports to (optionally) add to the caller. */
|
||||
String[] imports() default {};
|
||||
|
||||
/** The new static imports to (optionally) add to the caller. */
|
||||
String[] staticImports() default {};
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.IntList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link IntList} on top of a primitive array.
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class IntArrayList extends AbstractProtobufList<Integer>
|
||||
implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final IntArrayList EMPTY_LIST = new IntArrayList(new int[0], 0);
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
public static IntArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/** The backing store for the list. */
|
||||
private int[] array;
|
||||
|
||||
/**
|
||||
* The size of the list distinct from the length of the array. That is, it is the number of
|
||||
* elements set in the list.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** 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}.
|
||||
*/
|
||||
private IntArrayList(int[] other, int size) {
|
||||
array = other;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
ensureIsMutable();
|
||||
if (toIndex < fromIndex) {
|
||||
throw new IndexOutOfBoundsException("toIndex < fromIndex");
|
||||
}
|
||||
|
||||
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof IntArrayList)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
IntArrayList other = (IntArrayList) o;
|
||||
if (size != other.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] arr = other.array;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (array[i] != arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
result = (31 * result) + array[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new IntArrayList(Arrays.copyOf(array, capacity), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
if (!(element instanceof Integer)) {
|
||||
return -1;
|
||||
}
|
||||
int unboxedElement = (Integer) element;
|
||||
int numElems = size();
|
||||
for (int i = 0; i < numElems; i++) {
|
||||
if (array[i] == unboxedElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
return indexOf(element) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer set(int index, Integer element) {
|
||||
return setInt(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setInt(int index, int element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
int previousValue = array[index];
|
||||
array[index] = element;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Integer element) {
|
||||
addInt(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Integer element) {
|
||||
addInt(index, element);
|
||||
}
|
||||
|
||||
/** Like {@link #add(Integer)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addInt(int element) {
|
||||
ensureIsMutable();
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
int[] newArray = new int[length];
|
||||
|
||||
System.arraycopy(array, 0, newArray, 0, size);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = 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) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
int[] newArray = new int[length];
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Integer> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another IntArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof IntArrayList)) {
|
||||
return super.addAll(collection);
|
||||
}
|
||||
|
||||
IntArrayList list = (IntArrayList) collection;
|
||||
if (list.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int overflow = Integer.MAX_VALUE - size;
|
||||
if (overflow < list.size) {
|
||||
// We can't actually represent a list this large.
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
int newSize = size + list.size;
|
||||
if (newSize > array.length) {
|
||||
array = Arrays.copyOf(array, newSize);
|
||||
}
|
||||
|
||||
System.arraycopy(list.array, 0, array, size, list.size);
|
||||
size = newSize;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
int value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
|
||||
* {@link IndexOutOfBoundsException} if it is not.
|
||||
*
|
||||
* @param index the index to verify is in range
|
||||
*/
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.AbstractList;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.
|
||||
*
|
||||
* @author kenton@google.com (Kenton Varda)
|
||||
*/
|
||||
public final class Internal {
|
||||
|
||||
private Internal() {}
|
||||
|
||||
static final Charset US_ASCII = Charset.forName("US-ASCII");
|
||||
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}. */
|
||||
static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public static ByteBuffer copyByteBuffer(ByteBuffer source) {
|
||||
// Make a duplicate of the source ByteBuffer and read data from the
|
||||
// duplicate. This is to avoid affecting the source ByteBuffer's state.
|
||||
ByteBuffer temp = source.duplicate();
|
||||
// We want to copy all the data in the source ByteBuffer, not just the
|
||||
// remaining bytes.
|
||||
// View ByteBuffer as Buffer to avoid issue with covariant return types
|
||||
// See https://issues.apache.org/jira/browse/MRESOLVER-85
|
||||
((Buffer) temp).clear();
|
||||
ByteBuffer result = ByteBuffer.allocate(temp.capacity());
|
||||
result.put(temp);
|
||||
((Buffer) result).clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @param byteString the string to check
|
||||
* @return whether the byte array is round trippable
|
||||
*/
|
||||
public static boolean isValidUtf8(ByteString byteString) {
|
||||
return byteString.isValidUtf8();
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
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. */
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public interface EnumLiteMap<T extends EnumLite> {
|
||||
T findValueByNumber(int number);
|
||||
}
|
||||
|
||||
/** Interface for an object which verifies integers are in range. */
|
||||
public interface EnumVerifier {
|
||||
boolean isInRange(int number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for longs.
|
||||
*
|
||||
* @see Long#hashCode()
|
||||
*/
|
||||
public static int hashLong(long n) {
|
||||
return (int) (n ^ (n >>> 32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for implementing {@link Message#hashCode()} for booleans.
|
||||
*
|
||||
* @see Boolean#hashCode()
|
||||
*/
|
||||
public static int hashBoolean(boolean b) {
|
||||
return b ? 1231 : 1237;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static int hashEnum(EnumLite e) {
|
||||
return e.getNumber();
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
hash = 31 * hash + hashEnum(e);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
if (!Arrays.equals(a.get(i), b.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCode(List<byte[]> list) {
|
||||
int hash = 1;
|
||||
for (byte[] bytes : list) {
|
||||
hash = 31 * hash + hashCode(bytes);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** 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
|
||||
// hashCode() method will return the same value as the pure reflection
|
||||
// based hashCode() method.
|
||||
return Internal.hashCode(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/** 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
|
||||
// hashCode() method will return the same value as the pure reflection
|
||||
// based hashCode() method.
|
||||
int h = Internal.partialHash(length, bytes, offset, length);
|
||||
return h == 0 ? 1 : h;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
|
||||
if (a.capacity() != b.capacity()) {
|
||||
return false;
|
||||
}
|
||||
// ByteBuffer.equals() will only compare the remaining bytes, but we want to
|
||||
// compare all the content.
|
||||
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) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < a.size(); ++i) {
|
||||
if (!equalsByteBuffer(a.get(i), b.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCodeByteBuffer(List<ByteBuffer> list) {
|
||||
int hash = 1;
|
||||
for (ByteBuffer bytes : list) {
|
||||
hash = 31 * hash + hashCodeByteBuffer(bytes);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
|
||||
/** Helper method for implementing {@link Message#hashCode()} for bytes field. */
|
||||
public static int hashCodeByteBuffer(ByteBuffer bytes) {
|
||||
if (bytes.hasArray()) {
|
||||
// Fast path.
|
||||
int h = partialHash(bytes.capacity(), bytes.array(), bytes.arrayOffset(), bytes.capacity());
|
||||
return h == 0 ? 1 : h;
|
||||
} 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 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;
|
||||
duplicated.get(buffer, 0, length);
|
||||
h = partialHash(h, buffer, 0, length);
|
||||
}
|
||||
return h == 0 ? 1 : h;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends MessageLite> T getDefaultInstance(Class<T> clazz) {
|
||||
try {
|
||||
Method method = clazz.getMethod("getDefaultInstance");
|
||||
return (T) method.invoke(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to get default instance for " + clazz, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 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 coded input stream constant used in generated code. */
|
||||
public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
|
||||
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
|
||||
|
||||
|
||||
/** Helper method to merge two MessageLite instances. */
|
||||
static Object mergeMessage(Object destination, Object source) {
|
||||
return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
|
||||
*
|
||||
* <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. */
|
||||
public interface Converter<F, T> {
|
||||
T convert(F from);
|
||||
}
|
||||
|
||||
private final List<F> fromList;
|
||||
private final Converter<F, T> converter;
|
||||
|
||||
public ListAdapter(List<F> fromList, Converter<F, T> converter) {
|
||||
this.fromList = fromList;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index) {
|
||||
return converter.convert(fromList.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return fromList.size();
|
||||
}
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
public interface Converter<A, B> {
|
||||
B doForward(A object);
|
||||
|
||||
A doBackward(B object);
|
||||
}
|
||||
|
||||
public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
|
||||
final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
|
||||
return new Converter<Integer, T>() {
|
||||
@Override
|
||||
public T doForward(Integer value) {
|
||||
T result = enumMap.findValueByNumber(value);
|
||||
return result == null ? unrecognizedValue : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer doBackward(T value) {
|
||||
return value.getNumber();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final Map<K, RealValue> realMap;
|
||||
private final Converter<RealValue, V> valueConverter;
|
||||
|
||||
public MapAdapter(Map<K, RealValue> realMap, Converter<RealValue, V> valueConverter) {
|
||||
this.realMap = realMap;
|
||||
this.valueConverter = valueConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
RealValue result = realMap.get(key);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return valueConverter.doForward(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
RealValue oldValue = realMap.put(key, valueConverter.doBackward(value));
|
||||
if (oldValue == null) {
|
||||
return null;
|
||||
}
|
||||
return valueConverter.doForward(oldValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
return new SetAdapter(realMap.entrySet());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<java.util.Map.Entry<K, V>> iterator() {
|
||||
return new IteratorAdapter(realSet.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return realSet.size();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
this.realIterator = realIterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return realIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.Map.Entry<K, V> next() {
|
||||
return new EntryAdapter(realIterator.next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
realIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryAdapter implements Map.Entry<K, V> {
|
||||
private final Map.Entry<K, RealValue> realEntry;
|
||||
|
||||
public EntryAdapter(Map.Entry<K, RealValue> realEntry) {
|
||||
this.realEntry = realEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return realEntry.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return valueConverter.doForward(realEntry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
RealValue oldValue = realEntry.setValue(valueConverter.doBackward(value));
|
||||
if (oldValue == null) {
|
||||
return null;
|
||||
}
|
||||
return valueConverter.doForward(oldValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Map.Entry)) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
|
||||
return getKey().equals(other.getKey()) && getValue().equals(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return realEntry.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static interface ProtobufList<E> extends List<E>, RandomAccess {
|
||||
|
||||
/**
|
||||
* Makes this list immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
void makeImmutable();
|
||||
|
||||
/**
|
||||
* Returns whether this list can be modified via the publicly accessible {@link List} methods.
|
||||
*/
|
||||
boolean isModifiable();
|
||||
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
ProtobufList<E> mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Integers if
|
||||
* possible. Does not support null elements.
|
||||
*/
|
||||
public static interface IntList extends ProtobufList<Integer> {
|
||||
|
||||
/** 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. */
|
||||
void addInt(int element);
|
||||
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
@CanIgnoreReturnValue
|
||||
int setInt(int index, int element);
|
||||
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
IntList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Booleans if
|
||||
* possible. Does not support null elements.
|
||||
*/
|
||||
public static interface BooleanList extends ProtobufList<Boolean> {
|
||||
|
||||
/** 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. */
|
||||
void addBoolean(boolean element);
|
||||
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
@CanIgnoreReturnValue
|
||||
boolean setBoolean(int index, boolean element);
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
public static interface LongList extends ProtobufList<Long> {
|
||||
|
||||
/** 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. */
|
||||
void addLong(long element);
|
||||
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
@CanIgnoreReturnValue
|
||||
long setLong(int index, long element);
|
||||
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
LongList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Doubles if
|
||||
* possible. Does not support null elements.
|
||||
*/
|
||||
public static interface DoubleList extends ProtobufList<Double> {
|
||||
|
||||
/** 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. */
|
||||
void addDouble(double element);
|
||||
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
@CanIgnoreReturnValue
|
||||
double setDouble(int index, double element);
|
||||
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
DoubleList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link java.util.List} implementation that avoids boxing the elements into Floats if
|
||||
* possible. Does not support null elements.
|
||||
*/
|
||||
public static interface FloatList extends ProtobufList<Float> {
|
||||
|
||||
/** 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. */
|
||||
void addFloat(float element);
|
||||
|
||||
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
|
||||
@CanIgnoreReturnValue
|
||||
float setFloat(int index, float element);
|
||||
|
||||
/** Returns a mutable clone of this list with the specified capacity. */
|
||||
@Override
|
||||
FloatList mutableCopyWithCapacity(int capacity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thrown when a protocol message being parsed is invalid in some way. For instance,
|
||||
* it contains a malformed varint or a negative byte length.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class InvalidProtocolBufferException extends IOException {
|
||||
private static final long serialVersionUID = -1616151763072450476L;
|
||||
private MessageLite unfinishedMessage = null;
|
||||
private boolean wasThrownFromInputStream;
|
||||
|
||||
public InvalidProtocolBufferException(String description) {
|
||||
super(description);
|
||||
}
|
||||
|
||||
public InvalidProtocolBufferException(Exception e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public InvalidProtocolBufferException(String description, Exception e) {
|
||||
super(description, e);
|
||||
}
|
||||
|
||||
public InvalidProtocolBufferException(IOException e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public InvalidProtocolBufferException(String description, IOException e) {
|
||||
super(description, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches an unfinished message to the exception to support best-effort parsing in {@code
|
||||
* Parser} interface.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public MessageLite getUnfinishedMessage() {
|
||||
return unfinishedMessage;
|
||||
}
|
||||
|
||||
/** Set by CodedInputStream */
|
||||
void setThrownFromInputStream() {
|
||||
/* This write can be racy if the same exception is stored and then thrown by multiple custom
|
||||
* InputStreams on different threads. But since it only ever moves from false->true, there's no
|
||||
* problem. A thread checking this condition after catching this exception from a delegate
|
||||
* stream of CodedInputStream is guaranteed to always observe true, because a write on the same
|
||||
* thread set the value when the exception left the delegate. A thread checking the same
|
||||
* condition with an exception created by CodedInputStream is guaranteed to always see false,
|
||||
* because the exception has not been exposed to any code that could publish it to other threads
|
||||
* and cause a write.
|
||||
*/
|
||||
wasThrownFromInputStream = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows code catching IOException from CodedInputStream to tell whether this instance was thrown
|
||||
* by a delegate InputStream, rather than directly by a parse failure.
|
||||
*/
|
||||
boolean getThrownFromInputStream() {
|
||||
return wasThrownFromInputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException negativeSize() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"CodedInputStream encountered an embedded string or message "
|
||||
+ "which claimed to have negative size.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException malformedVarint() {
|
||||
return new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidTag() {
|
||||
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.");
|
||||
}
|
||||
|
||||
static InvalidWireTypeException invalidWireType() {
|
||||
return new InvalidWireTypeException("Protocol message tag had invalid wire type.");
|
||||
}
|
||||
|
||||
/** Exception indicating that an unexpected wire type was encountered for a field. */
|
||||
@ExperimentalApi
|
||||
public static class InvalidWireTypeException extends InvalidProtocolBufferException {
|
||||
private static final long serialVersionUID = 3283890091615336259L;
|
||||
|
||||
public InvalidWireTypeException(String description) {
|
||||
super(description);
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException sizeLimitExceeded() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message was too large. May be malicious. "
|
||||
+ "Use CodedInputStream.setSizeLimit() to increase the size limit.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException parseFailure() {
|
||||
return new InvalidProtocolBufferException("Failed to parse the message.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidUtf8() {
|
||||
return new InvalidProtocolBufferException("Protocol message had invalid UTF-8.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
||||
class IterableByteBufferInputStream extends InputStream {
|
||||
/** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */
|
||||
private Iterator<ByteBuffer> iterator;
|
||||
/** The current ByteBuffer; */
|
||||
private ByteBuffer currentByteBuffer;
|
||||
/** The number of ByteBuffers in the input data. */
|
||||
private int dataSize;
|
||||
/**
|
||||
* Current {@code ByteBuffer}'s index
|
||||
*
|
||||
* <p>If index equals dataSize, then all the data in the InputStream has been consumed
|
||||
*/
|
||||
private int currentIndex;
|
||||
/** The current position for current ByteBuffer */
|
||||
private int currentByteBufferPos;
|
||||
/** Whether current ByteBuffer has an array */
|
||||
private boolean hasArray;
|
||||
/**
|
||||
* If the current ByteBuffer is unsafe-direct based, currentArray is null; otherwise should be the
|
||||
* array inside ByteBuffer.
|
||||
*/
|
||||
private byte[] currentArray;
|
||||
/** Current ByteBuffer's array offset */
|
||||
private int currentArrayOffset;
|
||||
/**
|
||||
* If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this
|
||||
* ByteBuffer; otherwise should be zero.
|
||||
*/
|
||||
private long currentAddress;
|
||||
|
||||
IterableByteBufferInputStream(Iterable<ByteBuffer> data) {
|
||||
iterator = data.iterator();
|
||||
dataSize = 0;
|
||||
for (ByteBuffer unused : data) {
|
||||
dataSize++;
|
||||
}
|
||||
currentIndex = -1;
|
||||
|
||||
if (!getNextByteBuffer()) {
|
||||
currentByteBuffer = EMPTY_BYTE_BUFFER;
|
||||
currentIndex = 0;
|
||||
currentByteBufferPos = 0;
|
||||
currentAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getNextByteBuffer() {
|
||||
currentIndex++;
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
currentByteBuffer = iterator.next();
|
||||
currentByteBufferPos = currentByteBuffer.position();
|
||||
if (currentByteBuffer.hasArray()) {
|
||||
hasArray = true;
|
||||
currentArray = currentByteBuffer.array();
|
||||
currentArrayOffset = currentByteBuffer.arrayOffset();
|
||||
} else {
|
||||
hasArray = false;
|
||||
currentAddress = UnsafeUtil.addressOffset(currentByteBuffer);
|
||||
currentArray = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateCurrentByteBufferPos(int numberOfBytesRead) {
|
||||
currentByteBufferPos += numberOfBytesRead;
|
||||
if (currentByteBufferPos == currentByteBuffer.limit()) {
|
||||
getNextByteBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (currentIndex == dataSize) {
|
||||
return -1;
|
||||
}
|
||||
if (hasArray) {
|
||||
int result = currentArray[currentByteBufferPos + currentArrayOffset] & 0xFF;
|
||||
updateCurrentByteBufferPos(1);
|
||||
return result;
|
||||
} else {
|
||||
int result = UnsafeUtil.getByte(currentByteBufferPos + currentAddress) & 0xFF;
|
||||
updateCurrentByteBufferPos(1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] output, int offset, int length) throws IOException {
|
||||
if (currentIndex == dataSize) {
|
||||
return -1;
|
||||
}
|
||||
int remaining = currentByteBuffer.limit() - currentByteBufferPos;
|
||||
if (length > remaining) {
|
||||
length = remaining;
|
||||
}
|
||||
if (hasArray) {
|
||||
System.arraycopy(
|
||||
currentArray, currentByteBufferPos + currentArrayOffset, output, offset, length);
|
||||
updateCurrentByteBufferPos(length);
|
||||
} else {
|
||||
int prevPos = currentByteBuffer.position();
|
||||
currentByteBuffer.position(currentByteBufferPos);
|
||||
currentByteBuffer.get(output, offset, length);
|
||||
currentByteBuffer.position(prevPos);
|
||||
updateCurrentByteBufferPos(length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** Enum that identifies the Java types required to store protobuf fields. */
|
||||
@ExperimentalApi
|
||||
public enum JavaType {
|
||||
VOID(Void.class, Void.class, null),
|
||||
INT(int.class, Integer.class, 0),
|
||||
LONG(long.class, Long.class, 0L),
|
||||
FLOAT(float.class, Float.class, 0F),
|
||||
DOUBLE(double.class, Double.class, 0D),
|
||||
BOOLEAN(boolean.class, Boolean.class, false),
|
||||
STRING(String.class, String.class, ""),
|
||||
BYTE_STRING(ByteString.class, ByteString.class, ByteString.EMPTY),
|
||||
ENUM(int.class, Integer.class, null),
|
||||
MESSAGE(Object.class, Object.class, null);
|
||||
|
||||
private final Class<?> type;
|
||||
private final Class<?> boxedType;
|
||||
private final Object defaultDefault;
|
||||
|
||||
JavaType(Class<?> type, Class<?> boxedType, Object defaultDefault) {
|
||||
this.type = type;
|
||||
this.boxedType = boxedType;
|
||||
this.defaultDefault = defaultDefault;
|
||||
}
|
||||
|
||||
/** The default default value for fields of this type, if it's a primitive type. */
|
||||
public Object getDefaultDefault() {
|
||||
return defaultDefault;
|
||||
}
|
||||
|
||||
/** Gets the required type for a field that would hold a value of this type. */
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @return the boxedType */
|
||||
public Class<?> getBoxedType() {
|
||||
return boxedType;
|
||||
}
|
||||
|
||||
/** Indicates whether or not this {@link JavaType} can be applied to a field of the given type. */
|
||||
public boolean isValidType(Class<?> t) {
|
||||
return type.isAssignableFrom(t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.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 parses it on-demand.
|
||||
*
|
||||
* <p>Most methods are implemented in {@link LazyFieldLite} but this class can contain a
|
||||
* default instance of the message to provide {@code hashCode()}, {@code equals()}, and {@code
|
||||
* toString()}.
|
||||
*
|
||||
* @author xiangl@google.com (Xiang Li)
|
||||
*/
|
||||
public class LazyField extends LazyFieldLite {
|
||||
|
||||
/**
|
||||
* Carry a message's default instance which is used by {@code hashCode()}, {@code equals()}, and
|
||||
* {@code toString()}.
|
||||
*/
|
||||
private final MessageLite defaultInstance;
|
||||
|
||||
public LazyField(
|
||||
MessageLite defaultInstance, ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
super(extensionRegistry, bytes);
|
||||
|
||||
this.defaultInstance = defaultInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsDefaultInstance() {
|
||||
return super.containsDefaultInstance() || value == defaultInstance;
|
||||
}
|
||||
|
||||
public MessageLite getValue() {
|
||||
return getValue(defaultInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getValue().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return getValue().equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getValue().toString();
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private LazyEntry(Entry<K, LazyField> entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return entry.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
LazyField field = entry.getValue();
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
return field.getValue();
|
||||
}
|
||||
|
||||
public LazyField getField() {
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(Object value) {
|
||||
if (!(value instanceof MessageLite)) {
|
||||
throw new IllegalArgumentException(
|
||||
"LazyField now only used for MessageSet, "
|
||||
+ "and the value of MessageSet must be an instance of MessageLite");
|
||||
}
|
||||
return entry.getValue().setValue((MessageLite) value);
|
||||
}
|
||||
}
|
||||
|
||||
static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
|
||||
private Iterator<Entry<K, Object>> iterator;
|
||||
|
||||
public LazyIterator(Iterator<Entry<K, Object>> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Entry<K, Object> next() {
|
||||
Entry<K, ?> entry = iterator.next();
|
||||
if (entry.getValue() instanceof LazyField) {
|
||||
return new LazyEntry<K>((Entry<K, LazyField>) entry);
|
||||
}
|
||||
return (Entry<K, Object>) entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores the message in a
|
||||
* ByteString initially and then parses it on-demand.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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)
|
||||
*/
|
||||
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().
|
||||
*
|
||||
* <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
|
||||
* not it must parse the value from delayedBytes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <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}.
|
||||
*/
|
||||
private ExtensionRegistryLite extensionRegistry;
|
||||
|
||||
/**
|
||||
* The parsed value. When this is null and a caller needs access to the MessageLite value, then
|
||||
* {@code delayedBytes} will be parsed lazily at that time.
|
||||
*/
|
||||
protected volatile MessageLite value;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private volatile ByteString memoizedBytes;
|
||||
|
||||
/** 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 instance with a value. The LazyFieldLite may not be able to parse
|
||||
* the extensions in the value as it has no ExtensionRegistry.
|
||||
*/
|
||||
public static LazyFieldLite fromValue(MessageLite value) {
|
||||
LazyFieldLite lf = new LazyFieldLite();
|
||||
lf.setValue(value);
|
||||
return lf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
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
|
||||
// messages can by unequal but then be turned equal simply be invoking a getter on a lazy field.
|
||||
MessageLite value1 = value;
|
||||
MessageLite value2 = other.value;
|
||||
if (value1 == null && value2 == null) {
|
||||
return toByteString().equals(other.toByteString());
|
||||
} else if (value1 != null && value2 != null) {
|
||||
return value1.equals(value2);
|
||||
} else if (value1 != null) {
|
||||
return value1.equals(other.getValue(value1.getDefaultInstanceForType()));
|
||||
} else {
|
||||
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
|
||||
// hash codes but evaluate to equivalent messages. And we have no facility for constructing
|
||||
// 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.
|
||||
*/
|
||||
public boolean containsDefaultInstance() {
|
||||
return memoizedBytes == ByteString.EMPTY
|
||||
|| value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the value state of this instance.
|
||||
*
|
||||
* <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
|
||||
// value, but there is no guarantee that it will contain all extensions that were directly set
|
||||
// on the values that need to be merged.
|
||||
delayedBytes = null;
|
||||
value = null;
|
||||
memoizedBytes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the contents of this LazyField.
|
||||
*
|
||||
* <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;
|
||||
this.value = other.value;
|
||||
this.memoizedBytes = other.memoizedBytes;
|
||||
// If the other LazyFieldLite was created by directly setting the value rather than first by
|
||||
// parsing, then it will not have an extensionRegistry. In this case we hold on to the existing
|
||||
// extensionRegistry, which has no guarantees that it has all the extensions that will be
|
||||
// directly set on the value.
|
||||
if (other.extensionRegistry != null) {
|
||||
this.extensionRegistry = other.extensionRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public MessageLite getValue(MessageLite defaultInstance) {
|
||||
ensureInitialized(defaultInstance);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public MessageLite setValue(MessageLite value) {
|
||||
MessageLite originalValue = this.value;
|
||||
this.delayedBytes = null;
|
||||
this.memoizedBytes = null;
|
||||
this.value = value;
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges another instance's contents. In some cases may drop some extensions if both fields
|
||||
* 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.
|
||||
*/
|
||||
public void merge(LazyFieldLite other) {
|
||||
if (other.containsDefaultInstance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.containsDefaultInstance()) {
|
||||
set(other);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the other field has an extension registry but this does not, copy over the other extension
|
||||
// registry.
|
||||
if (this.extensionRegistry == null) {
|
||||
this.extensionRegistry = other.extensionRegistry;
|
||||
}
|
||||
|
||||
// In the case that both of them are not parsed we simply concatenate the bytes to save time. In
|
||||
// the (probably rare) case that they have different extension registries there is a chance that
|
||||
// some of the extensions may be dropped, but the tradeoff of making this operation fast seems
|
||||
// to outway the benefits of combining the extension registries, which is not normally done for
|
||||
// lite protos anyways.
|
||||
if (this.delayedBytes != null && other.delayedBytes != null) {
|
||||
this.delayedBytes = this.delayedBytes.concat(other.delayedBytes);
|
||||
return;
|
||||
}
|
||||
|
||||
// At least one is parsed and both contain data. We won't drop any extensions here directly, but
|
||||
// in the case that the extension registries are not the same then we might in the future if we
|
||||
// need to serialize and parse a message again.
|
||||
if (this.value == null && other.value != null) {
|
||||
setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry));
|
||||
return;
|
||||
} else if (this.value != null && other.value == null) {
|
||||
setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry));
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
*/
|
||||
public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
if (this.containsDefaultInstance()) {
|
||||
setByteString(input.readBytes(), extensionRegistry);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the other field has an extension registry but this does not, copy over the other extension
|
||||
// registry.
|
||||
if (this.extensionRegistry == null) {
|
||||
this.extensionRegistry = extensionRegistry;
|
||||
}
|
||||
|
||||
// In the case that both of them are not parsed we simply concatenate the bytes to save time. In
|
||||
// the (probably rare) case that they have different extension registries there is a chance that
|
||||
// some of the extensions may be dropped, but the tradeoff of making this operation fast seems
|
||||
// to outway the benefits of combining the extension registries, which is not normally done for
|
||||
// lite protos anyways.
|
||||
if (this.delayedBytes != null) {
|
||||
setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry);
|
||||
return;
|
||||
}
|
||||
|
||||
// We are parsed and both contain data. We won't drop any extensions here directly, but in the
|
||||
// case that the extension registries are not the same then we might in the future if we
|
||||
// need to serialize and parse a message again.
|
||||
try {
|
||||
setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build());
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
|
||||
// was invalid.
|
||||
}
|
||||
}
|
||||
|
||||
private static MessageLite mergeValueAndBytes(
|
||||
MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
|
||||
try {
|
||||
return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build();
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
|
||||
// was invalid.
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets this field with bytes to delay-parse. */
|
||||
public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
|
||||
checkArguments(extensionRegistry, bytes);
|
||||
this.delayedBytes = bytes;
|
||||
this.extensionRegistry = extensionRegistry;
|
||||
this.value = null;
|
||||
this.memoizedBytes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
// have memoized serialized size based off of it.
|
||||
if (memoizedBytes != null) {
|
||||
return memoizedBytes.size();
|
||||
} else if (delayedBytes != null) {
|
||||
return delayedBytes.size();
|
||||
} else if (value != null) {
|
||||
return value.getSerializedSize();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a BytesString for this field in a thread-safe way. */
|
||||
public ByteString toByteString() {
|
||||
if (memoizedBytes != null) {
|
||||
return memoizedBytes;
|
||||
}
|
||||
// We *must* return delayed bytes if it was set because the dependent messages may have
|
||||
// memoized serialized size based off of it.
|
||||
if (delayedBytes != null) {
|
||||
return delayedBytes;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (memoizedBytes != null) {
|
||||
return memoizedBytes;
|
||||
}
|
||||
if (value == null) {
|
||||
memoizedBytes = ByteString.EMPTY;
|
||||
} else {
|
||||
memoizedBytes = value.toByteString();
|
||||
}
|
||||
return memoizedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes this lazy field into a {@link Writer}. */
|
||||
void writeTo(Writer writer, int fieldNumber) throws IOException {
|
||||
if (memoizedBytes != null) {
|
||||
writer.writeBytes(fieldNumber, memoizedBytes);
|
||||
} else if (delayedBytes != null) {
|
||||
writer.writeBytes(fieldNumber, delayedBytes);
|
||||
} else if (value != null) {
|
||||
writer.writeMessage(fieldNumber, value);
|
||||
} else {
|
||||
writer.writeBytes(fieldNumber, ByteString.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
/** Might lazily parse the bytes that were previously passed in. Is thread-safe. */
|
||||
protected void ensureInitialized(MessageLite defaultInstance) {
|
||||
if (value != null) {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (value != null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (delayedBytes != null) {
|
||||
// The extensionRegistry shouldn't be null here since we have delayedBytes.
|
||||
MessageLite parsedValue =
|
||||
defaultInstance.getParserForType().parseFrom(delayedBytes, extensionRegistry);
|
||||
this.value = parsedValue;
|
||||
this.memoizedBytes = delayedBytes;
|
||||
} else {
|
||||
this.value = defaultInstance;
|
||||
this.memoizedBytes = ByteString.EMPTY;
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
|
||||
// was invalid.
|
||||
this.value = defaultInstance;
|
||||
this.memoizedBytes = ByteString.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
||||
if (extensionRegistry == null) {
|
||||
throw new NullPointerException("found null ExtensionRegistry");
|
||||
}
|
||||
if (bytes == null) {
|
||||
throw new NullPointerException("found null ByteString");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
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.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public class LazyStringArrayList extends AbstractProtobufList<String>
|
||||
implements LazyStringList, RandomAccess {
|
||||
|
||||
private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
static LazyStringArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
// For compatibility with older runtimes.
|
||||
public static final LazyStringList EMPTY = EMPTY_LIST;
|
||||
|
||||
private final List<Object> list;
|
||||
|
||||
public LazyStringArrayList() {
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
public LazyStringArrayList(int initialCapacity) {
|
||||
this(new ArrayList<Object>(initialCapacity));
|
||||
}
|
||||
|
||||
public LazyStringArrayList(LazyStringList from) {
|
||||
list = new ArrayList<Object>(from.size());
|
||||
addAll(from);
|
||||
}
|
||||
|
||||
public LazyStringArrayList(List<String> from) {
|
||||
this(new ArrayList<Object>(from));
|
||||
}
|
||||
|
||||
private LazyStringArrayList(ArrayList<Object> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
ArrayList<Object> newList = new ArrayList<Object>(capacity);
|
||||
newList.addAll(list);
|
||||
return new LazyStringArrayList(newList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(int index) {
|
||||
Object o = list.get(index);
|
||||
if (o instanceof String) {
|
||||
return (String) o;
|
||||
} else if (o instanceof ByteString) {
|
||||
ByteString bs = (ByteString) o;
|
||||
String s = bs.toStringUtf8();
|
||||
if (bs.isValidUtf8()) {
|
||||
list.set(index, s);
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
byte[] ba = (byte[]) o;
|
||||
String s = Internal.toStringUtf8(ba);
|
||||
if (Internal.isValidUtf8(ba)) {
|
||||
list.set(index, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String set(int index, String s) {
|
||||
ensureIsMutable();
|
||||
Object o = list.set(index, s);
|
||||
return asString(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, String element) {
|
||||
ensureIsMutable();
|
||||
list.add(index, element);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private void add(int index, ByteString element) {
|
||||
ensureIsMutable();
|
||||
list.add(index, element);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private void add(int index, byte[] element) {
|
||||
ensureIsMutable();
|
||||
list.add(index, element);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends String> c) {
|
||||
// The default implementation of AbstractCollection.addAll(Collection)
|
||||
// delegates to add(Object). This implementation instead delegates to
|
||||
// addAll(int, Collection), which makes a special case for Collections
|
||||
// which are instances of LazyStringList.
|
||||
return addAll(size(), c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends String> c) {
|
||||
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;
|
||||
boolean ret = list.addAll(index, collection);
|
||||
modCount++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllByteString(Collection<? extends ByteString> values) {
|
||||
ensureIsMutable();
|
||||
boolean ret = list.addAll(values);
|
||||
modCount++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllByteArray(Collection<byte[]> c) {
|
||||
ensureIsMutable();
|
||||
boolean ret = list.addAll(c);
|
||||
modCount++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(int index) {
|
||||
ensureIsMutable();
|
||||
Object o = list.remove(index);
|
||||
modCount++;
|
||||
return asString(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
ensureIsMutable();
|
||||
list.clear();
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(ByteString element) {
|
||||
ensureIsMutable();
|
||||
list.add(element);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(byte[] element) {
|
||||
ensureIsMutable();
|
||||
list.add(element);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRaw(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString getByteString(int index) {
|
||||
Object o = list.get(index);
|
||||
ByteString b = asByteString(o);
|
||||
if (b != o) {
|
||||
list.set(index, b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getByteArray(int index) {
|
||||
Object o = list.get(index);
|
||||
byte[] b = asByteArray(o);
|
||||
if (b != o) {
|
||||
list.set(index, b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int index, ByteString s) {
|
||||
setAndReturn(index, s);
|
||||
}
|
||||
|
||||
private Object setAndReturn(int index, ByteString s) {
|
||||
ensureIsMutable();
|
||||
return list.set(index, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int index, byte[] s) {
|
||||
setAndReturn(index, s);
|
||||
}
|
||||
|
||||
private Object setAndReturn(int index, byte[] s) {
|
||||
ensureIsMutable();
|
||||
return list.set(index, s);
|
||||
}
|
||||
|
||||
private static String asString(Object o) {
|
||||
if (o instanceof String) {
|
||||
return (String) o;
|
||||
} else if (o instanceof ByteString) {
|
||||
return ((ByteString) o).toStringUtf8();
|
||||
} else {
|
||||
return Internal.toStringUtf8((byte[]) o);
|
||||
}
|
||||
}
|
||||
|
||||
private static ByteString asByteString(Object o) {
|
||||
if (o instanceof ByteString) {
|
||||
return (ByteString) o;
|
||||
} else if (o instanceof String) {
|
||||
return ByteString.copyFromUtf8((String) o);
|
||||
} else {
|
||||
return ByteString.copyFrom((byte[]) o);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] asByteArray(Object o) {
|
||||
if (o instanceof byte[]) {
|
||||
return (byte[]) o;
|
||||
} else if (o instanceof String) {
|
||||
return Internal.toByteArray((String) o);
|
||||
} else {
|
||||
return ((ByteString) o).toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getUnderlyingElements() {
|
||||
return Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeFrom(LazyStringList other) {
|
||||
ensureIsMutable();
|
||||
for (Object o : other.getUnderlyingElements()) {
|
||||
if (o instanceof byte[]) {
|
||||
byte[] b = (byte[]) o;
|
||||
// Byte array's content is mutable so they should be copied rather than
|
||||
// shared when merging from one message to another.
|
||||
list.add(Arrays.copyOf(b, b.length));
|
||||
} else {
|
||||
list.add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ByteArrayListView extends AbstractList<byte[]> implements RandomAccess {
|
||||
private final LazyStringArrayList list;
|
||||
|
||||
ByteArrayListView(LazyStringArrayList list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(int index) {
|
||||
return list.getByteArray(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] set(int index, byte[] s) {
|
||||
Object o = list.setAndReturn(index, s);
|
||||
modCount++;
|
||||
return asByteArray(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, byte[] s) {
|
||||
list.add(index, s);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] remove(int index) {
|
||||
Object o = list.remove(index);
|
||||
modCount++;
|
||||
return asByteArray(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<byte[]> asByteArrayList() {
|
||||
return new ByteArrayListView(this);
|
||||
}
|
||||
|
||||
private static class ByteStringListView extends AbstractList<ByteString> implements RandomAccess {
|
||||
private final LazyStringArrayList list;
|
||||
|
||||
ByteStringListView(LazyStringArrayList list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString get(int index) {
|
||||
return list.getByteString(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString set(int index, ByteString s) {
|
||||
Object o = list.setAndReturn(index, s);
|
||||
modCount++;
|
||||
return asByteString(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, ByteString s) {
|
||||
list.add(index, s);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString remove(int index) {
|
||||
Object o = list.remove(index);
|
||||
modCount++;
|
||||
return asByteString(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ByteString> asByteStringList() {
|
||||
return new ByteStringListView(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyStringList getUnmodifiableView() {
|
||||
if (isModifiable()) {
|
||||
return new UnmodifiableLazyStringList(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.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.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
public interface LazyStringList extends ProtocolStringList {
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this list as 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()})
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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()})
|
||||
*/
|
||||
Object getRaw(int index);
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this list as byte[].
|
||||
*
|
||||
* @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()})
|
||||
*/
|
||||
byte[] getByteArray(int index);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void add(ByteString element);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void add(byte[] element);
|
||||
|
||||
/**
|
||||
* 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()})
|
||||
*/
|
||||
void set(int index, ByteString element);
|
||||
|
||||
/**
|
||||
* 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()})
|
||||
*/
|
||||
void set(int index, byte[] element);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean addAllByteString(Collection<? extends ByteString> c);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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}.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
List<byte[]> asByteArrayList();
|
||||
|
||||
/** Returns an unmodifiable view of the list. */
|
||||
LazyStringList getUnmodifiableView();
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class that aids in properly manipulating list fields for either the lite or full runtime.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
abstract class ListFieldSchema {
|
||||
// Disallow construction.
|
||||
private ListFieldSchema() {}
|
||||
|
||||
private static final ListFieldSchema FULL_INSTANCE = new ListFieldSchemaFull();
|
||||
private static final ListFieldSchema LITE_INSTANCE = new ListFieldSchemaLite();
|
||||
|
||||
abstract <L> List<L> mutableListAt(Object msg, long offset);
|
||||
|
||||
abstract void makeImmutableListAt(Object msg, long offset);
|
||||
|
||||
abstract <L> void mergeListsAt(Object msg, Object otherMsg, long offset);
|
||||
|
||||
static ListFieldSchema full() {
|
||||
return FULL_INSTANCE;
|
||||
}
|
||||
|
||||
static ListFieldSchema lite() {
|
||||
return LITE_INSTANCE;
|
||||
}
|
||||
|
||||
/** Implementation for the full runtime. */
|
||||
private static final class ListFieldSchemaFull extends ListFieldSchema {
|
||||
|
||||
private static final Class<?> UNMODIFIABLE_LIST_CLASS =
|
||||
Collections.unmodifiableList(Collections.emptyList()).getClass();
|
||||
|
||||
@Override
|
||||
<L> List<L> mutableListAt(Object message, long offset) {
|
||||
return mutableListAt(message, offset, AbstractProtobufList.DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
void makeImmutableListAt(Object message, long offset) {
|
||||
List<?> list = (List<?>) UnsafeUtil.getObject(message, offset);
|
||||
Object immutable = null;
|
||||
if (list instanceof LazyStringList) {
|
||||
immutable = ((LazyStringList) list).getUnmodifiableView();
|
||||
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
|
||||
// already immutable
|
||||
return;
|
||||
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
|
||||
if (((ProtobufList<?>) list).isModifiable()) {
|
||||
((ProtobufList<?>) list).makeImmutable();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
immutable = Collections.unmodifiableList((List<?>) list);
|
||||
}
|
||||
UnsafeUtil.putObject(message, offset, immutable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <L> List<L> mutableListAt(Object message, long offset, int additionalCapacity) {
|
||||
List<L> list = getList(message, offset);
|
||||
if (list.isEmpty()) {
|
||||
if (list instanceof LazyStringList) {
|
||||
list = (List<L>) new LazyStringArrayList(additionalCapacity);
|
||||
} else if (list instanceof PrimitiveNonBoxingCollection && list instanceof ProtobufList) {
|
||||
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(additionalCapacity);
|
||||
} else {
|
||||
list = new ArrayList<L>(additionalCapacity);
|
||||
}
|
||||
UnsafeUtil.putObject(message, offset, list);
|
||||
} else if (UNMODIFIABLE_LIST_CLASS.isAssignableFrom(list.getClass())) {
|
||||
ArrayList<L> newList = new ArrayList<L>(list.size() + additionalCapacity);
|
||||
newList.addAll(list);
|
||||
list = newList;
|
||||
UnsafeUtil.putObject(message, offset, list);
|
||||
} else if (list instanceof UnmodifiableLazyStringList) {
|
||||
LazyStringArrayList newList = new LazyStringArrayList(list.size() + additionalCapacity);
|
||||
newList.addAll((UnmodifiableLazyStringList) list);
|
||||
list = (List<L>) newList;
|
||||
UnsafeUtil.putObject(message, offset, list);
|
||||
} else if (list instanceof PrimitiveNonBoxingCollection
|
||||
&& list instanceof ProtobufList
|
||||
&& !((ProtobufList<L>) list).isModifiable()) {
|
||||
list = ((ProtobufList<L>) list).mutableCopyWithCapacity(list.size() + additionalCapacity);
|
||||
UnsafeUtil.putObject(message, offset, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
|
||||
List<E> other = getList(otherMsg, offset);
|
||||
List<E> mine = mutableListAt(msg, offset, other.size());
|
||||
|
||||
int size = mine.size();
|
||||
int otherSize = other.size();
|
||||
if (size > 0 && otherSize > 0) {
|
||||
mine.addAll(other);
|
||||
}
|
||||
|
||||
List<E> merged = size > 0 ? mine : other;
|
||||
UnsafeUtil.putObject(msg, offset, merged);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> List<E> getList(Object message, long offset) {
|
||||
return (List<E>) UnsafeUtil.getObject(message, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation for the lite runtime. */
|
||||
private static final class ListFieldSchemaLite extends ListFieldSchema {
|
||||
|
||||
@Override
|
||||
<L> List<L> mutableListAt(Object message, long offset) {
|
||||
ProtobufList<L> list = getProtobufList(message, offset);
|
||||
if (!list.isModifiable()) {
|
||||
int size = list.size();
|
||||
list =
|
||||
list.mutableCopyWithCapacity(
|
||||
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
|
||||
UnsafeUtil.putObject(message, offset, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
void makeImmutableListAt(Object message, long offset) {
|
||||
ProtobufList<?> list = getProtobufList(message, offset);
|
||||
list.makeImmutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> void mergeListsAt(Object msg, Object otherMsg, long offset) {
|
||||
ProtobufList<E> mine = getProtobufList(msg, offset);
|
||||
ProtobufList<E> other = getProtobufList(otherMsg, offset);
|
||||
|
||||
int size = mine.size();
|
||||
int otherSize = other.size();
|
||||
if (size > 0 && otherSize > 0) {
|
||||
if (!mine.isModifiable()) {
|
||||
mine = mine.mutableCopyWithCapacity(size + otherSize);
|
||||
}
|
||||
mine.addAll(other);
|
||||
}
|
||||
|
||||
ProtobufList<E> merged = size > 0 ? mine : other;
|
||||
UnsafeUtil.putObject(msg, offset, merged);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> ProtobufList<E> getProtobufList(Object message, long offset) {
|
||||
return (ProtobufList<E>) UnsafeUtil.getObject(message, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.LongList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/**
|
||||
* An implementation of {@link LongList} on top of a primitive array.
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class LongArrayList extends AbstractProtobufList<Long>
|
||||
implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final LongArrayList EMPTY_LIST = new LongArrayList(new long[0], 0);
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
public static LongArrayList emptyList() {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
/** The backing store for the list. */
|
||||
private long[] array;
|
||||
|
||||
/**
|
||||
* The size of the list distinct from the length of the array. That is, it is the number of
|
||||
* elements set in the list.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** 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}.
|
||||
*/
|
||||
private LongArrayList(long[] other, int size) {
|
||||
array = other;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
ensureIsMutable();
|
||||
if (toIndex < fromIndex) {
|
||||
throw new IndexOutOfBoundsException("toIndex < fromIndex");
|
||||
}
|
||||
|
||||
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof LongArrayList)) {
|
||||
return super.equals(o);
|
||||
}
|
||||
LongArrayList other = (LongArrayList) o;
|
||||
if (size != other.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final long[] arr = other.array;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (array[i] != arr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
result = (31 * result) + Internal.hashLong(array[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongList mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new LongArrayList(Arrays.copyOf(array, capacity), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long get(int index) {
|
||||
return getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
if (!(element instanceof Long)) {
|
||||
return -1;
|
||||
}
|
||||
long unboxedElement = (Long) element;
|
||||
int numElems = size();
|
||||
for (int i = 0; i < numElems; i++) {
|
||||
if (array[i] == unboxedElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object element) {
|
||||
return indexOf(element) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long set(int index, Long element) {
|
||||
return setLong(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long setLong(int index, long element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
long previousValue = array[index];
|
||||
array[index] = element;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Long element) {
|
||||
addLong(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Long element) {
|
||||
addLong(index, element);
|
||||
}
|
||||
|
||||
/** Like {@link #add(Long)} but more efficient in that it doesn't box the element. */
|
||||
@Override
|
||||
public void addLong(long element) {
|
||||
ensureIsMutable();
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
long[] newArray = new long[length];
|
||||
|
||||
System.arraycopy(array, 0, newArray, 0, size);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = 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) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
long[] newArray = new long[length];
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Long> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another LongArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof LongArrayList)) {
|
||||
return super.addAll(collection);
|
||||
}
|
||||
|
||||
LongArrayList list = (LongArrayList) collection;
|
||||
if (list.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int overflow = Integer.MAX_VALUE - size;
|
||||
if (overflow < list.size) {
|
||||
// We can't actually represent a list this large.
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
int newSize = size + list.size;
|
||||
if (newSize > array.length) {
|
||||
array = Arrays.copyOf(array, newSize);
|
||||
}
|
||||
|
||||
System.arraycopy(list.array, 0, array, size, list.size);
|
||||
size = newSize;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
long value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
|
||||
* {@link IndexOutOfBoundsException} if it is not.
|
||||
*
|
||||
* @param index the index to verify is in range
|
||||
*/
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
/**
|
||||
* Dynamically generates a manifest-based (i.e. table-based) schema for a given protobuf message.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
@ExperimentalApi
|
||||
final class ManifestSchemaFactory implements SchemaFactory {
|
||||
|
||||
private final MessageInfoFactory messageInfoFactory;
|
||||
|
||||
public ManifestSchemaFactory() {
|
||||
this(getDefaultMessageInfoFactory());
|
||||
}
|
||||
|
||||
private ManifestSchemaFactory(MessageInfoFactory messageInfoFactory) {
|
||||
this.messageInfoFactory = checkNotNull(messageInfoFactory, "messageInfoFactory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Schema<T> createSchema(Class<T> messageType) {
|
||||
SchemaUtil.requireGeneratedMessage(messageType);
|
||||
|
||||
MessageInfo messageInfo = messageInfoFactory.messageInfoFor(messageType);
|
||||
|
||||
// MessageSet has a special schema.
|
||||
if (messageInfo.isMessageSetWireFormat()) {
|
||||
if (GeneratedMessageLite.class.isAssignableFrom(messageType)) {
|
||||
return MessageSetSchema.newSchema(
|
||||
SchemaUtil.unknownFieldSetLiteSchema(),
|
||||
ExtensionSchemas.lite(),
|
||||
messageInfo.getDefaultInstance());
|
||||
}
|
||||
return MessageSetSchema.newSchema(
|
||||
SchemaUtil.proto2UnknownFieldSetSchema(),
|
||||
ExtensionSchemas.full(),
|
||||
messageInfo.getDefaultInstance());
|
||||
}
|
||||
|
||||
return newSchema(messageType, messageInfo);
|
||||
}
|
||||
|
||||
private static <T> Schema<T> newSchema(Class<T> messageType, MessageInfo messageInfo) {
|
||||
if (GeneratedMessageLite.class.isAssignableFrom(messageType)) {
|
||||
return isProto2(messageInfo)
|
||||
? MessageSchema.newSchema(
|
||||
messageType,
|
||||
messageInfo,
|
||||
NewInstanceSchemas.lite(),
|
||||
ListFieldSchema.lite(),
|
||||
SchemaUtil.unknownFieldSetLiteSchema(),
|
||||
ExtensionSchemas.lite(),
|
||||
MapFieldSchemas.lite())
|
||||
: MessageSchema.newSchema(
|
||||
messageType,
|
||||
messageInfo,
|
||||
NewInstanceSchemas.lite(),
|
||||
ListFieldSchema.lite(),
|
||||
SchemaUtil.unknownFieldSetLiteSchema(),
|
||||
/* extensionSchema= */ null,
|
||||
MapFieldSchemas.lite());
|
||||
}
|
||||
return isProto2(messageInfo)
|
||||
? MessageSchema.newSchema(
|
||||
messageType,
|
||||
messageInfo,
|
||||
NewInstanceSchemas.full(),
|
||||
ListFieldSchema.full(),
|
||||
SchemaUtil.proto2UnknownFieldSetSchema(),
|
||||
ExtensionSchemas.full(),
|
||||
MapFieldSchemas.full())
|
||||
: MessageSchema.newSchema(
|
||||
messageType,
|
||||
messageInfo,
|
||||
NewInstanceSchemas.full(),
|
||||
ListFieldSchema.full(),
|
||||
SchemaUtil.proto3UnknownFieldSetSchema(),
|
||||
/* extensionSchema= */ null,
|
||||
MapFieldSchemas.full());
|
||||
}
|
||||
|
||||
private static boolean isProto2(MessageInfo messageInfo) {
|
||||
return messageInfo.getSyntax() == ProtoSyntax.PROTO2;
|
||||
}
|
||||
|
||||
private static MessageInfoFactory getDefaultMessageInfoFactory() {
|
||||
return new CompositeMessageInfoFactory(
|
||||
GeneratedMessageInfoFactory.getInstance(), getDescriptorMessageInfoFactory());
|
||||
}
|
||||
|
||||
private static class CompositeMessageInfoFactory implements MessageInfoFactory {
|
||||
private MessageInfoFactory[] factories;
|
||||
|
||||
CompositeMessageInfoFactory(MessageInfoFactory... factories) {
|
||||
this.factories = factories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Class<?> clazz) {
|
||||
for (MessageInfoFactory factory : factories) {
|
||||
if (factory.isSupported(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo messageInfoFor(Class<?> clazz) {
|
||||
for (MessageInfoFactory factory : factories) {
|
||||
if (factory.isSupported(clazz)) {
|
||||
return factory.messageInfoFor(clazz);
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"No factory is available for message type: " + clazz.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static final MessageInfoFactory EMPTY_FACTORY =
|
||||
new MessageInfoFactory() {
|
||||
@Override
|
||||
public boolean isSupported(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo messageInfoFor(Class<?> clazz) {
|
||||
throw new IllegalStateException("This should never be called.");
|
||||
}
|
||||
};
|
||||
|
||||
private static MessageInfoFactory getDescriptorMessageInfoFactory() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.google.protobuf.DescriptorMessageInfoFactory");
|
||||
return (MessageInfoFactory) clazz.getDeclaredMethod("getInstance").invoke(null);
|
||||
} catch (Exception e) {
|
||||
return EMPTY_FACTORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Implements MapEntry messages.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <p>Protobuf internal. Users shouldn't use this class.
|
||||
*/
|
||||
public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> {
|
||||
|
||||
public final Descriptor descriptor;
|
||||
public final Parser<MapEntry<K, V>> parser;
|
||||
|
||||
public Metadata(
|
||||
Descriptor descriptor,
|
||||
MapEntry<K, V> defaultInstance,
|
||||
WireFormat.FieldType keyType,
|
||||
WireFormat.FieldType valueType) {
|
||||
super(keyType, defaultInstance.key, valueType, defaultInstance.value);
|
||||
this.descriptor = descriptor;
|
||||
this.parser =
|
||||
new AbstractParser<MapEntry<K, V>>() {
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> parsePartialFrom(
|
||||
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private final K key;
|
||||
private final V value;
|
||||
private final Metadata<K, V> metadata;
|
||||
|
||||
/** Create a default MapEntry instance. */
|
||||
private MapEntry(
|
||||
Descriptor descriptor,
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
this.key = defaultKey;
|
||||
this.value = defaultValue;
|
||||
this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
|
||||
}
|
||||
|
||||
/** Create a MapEntry with the provided key and value. */
|
||||
@SuppressWarnings("unchecked")
|
||||
private MapEntry(Metadata metadata, K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
/** Parsing constructor. */
|
||||
private MapEntry(
|
||||
Metadata<K, V> metadata, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
this.metadata = metadata;
|
||||
Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry);
|
||||
this.key = entry.getKey();
|
||||
this.value = entry.getValue();
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(this);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default MapEntry instance. A default MapEntry instance should be created only once for
|
||||
* each map entry message type. Generated code should store the created default instance and use
|
||||
* it later to create new MapEntry messages of the same type.
|
||||
*/
|
||||
public static <K, V> MapEntry<K, V> newDefaultInstance(
|
||||
Descriptor descriptor,
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
return new MapEntry<K, V>(descriptor, keyType, defaultKey, valueType, defaultValue);
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private volatile int cachedSerializedSize = -1;
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
if (cachedSerializedSize != -1) {
|
||||
return cachedSerializedSize;
|
||||
}
|
||||
|
||||
int size = MapEntryLite.computeSerializedSize(metadata, key, value);
|
||||
cachedSerializedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(CodedOutputStream output) throws IOException {
|
||||
MapEntryLite.writeTo(output, metadata, key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return isInitialized(metadata, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser<MapEntry<K, V>> getParserForType() {
|
||||
return metadata.parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> newBuilderForType() {
|
||||
return new Builder<K, V>(metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> toBuilder() {
|
||||
return new Builder<K, V>(metadata, key, value, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> getDefaultInstanceForType() {
|
||||
return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return metadata.descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
|
||||
for (final FieldDescriptor field : metadata.descriptor.getFields()) {
|
||||
if (hasField(field)) {
|
||||
result.put(field, getField(field));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(result);
|
||||
}
|
||||
|
||||
private void checkFieldDescriptor(FieldDescriptor field) {
|
||||
if (field.getContainingType() != metadata.descriptor) {
|
||||
throw new RuntimeException(
|
||||
"Wrong FieldDescriptor \""
|
||||
+ field.getFullName()
|
||||
+ "\" used in message \""
|
||||
+ metadata.descriptor.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
;
|
||||
// A MapEntry always contains two fields.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
Object result = field.getNumber() == 1 ? getKey() : getValue();
|
||||
// Convert enums to EnumValueDescriptor.
|
||||
if (field.getType() == FieldDescriptor.Type.ENUM) {
|
||||
result = field.getEnumType().findValueByNumberCreatingIfUnknown((java.lang.Integer) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
/** Builder to create {@link MapEntry} messages. */
|
||||
public static class Builder<K, V> extends AbstractMessage.Builder<Builder<K, V>> {
|
||||
private final Metadata<K, V> metadata;
|
||||
private K key;
|
||||
private V value;
|
||||
private boolean hasKey;
|
||||
private boolean hasValue;
|
||||
|
||||
private Builder(Metadata<K, V> metadata) {
|
||||
this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
|
||||
}
|
||||
|
||||
private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
|
||||
this.metadata = metadata;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.hasKey = hasKey;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Builder<K, V> setKey(K key) {
|
||||
this.key = key;
|
||||
this.hasKey = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> clearKey() {
|
||||
this.key = metadata.defaultKey;
|
||||
this.hasKey = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> setValue(V value) {
|
||||
this.value = value;
|
||||
this.hasValue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> clearValue() {
|
||||
this.value = metadata.defaultValue;
|
||||
this.hasValue = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> build() {
|
||||
MapEntry<K, V> result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> buildPartial() {
|
||||
return new MapEntry<K, V>(metadata, key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return metadata.descriptor;
|
||||
}
|
||||
|
||||
private void checkFieldDescriptor(FieldDescriptor field) {
|
||||
if (field.getContainingType() != metadata.descriptor) {
|
||||
throw new RuntimeException(
|
||||
"Wrong FieldDescriptor \""
|
||||
+ field.getFullName()
|
||||
+ "\" used in message \""
|
||||
+ metadata.descriptor.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message.Builder newBuilderForField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
;
|
||||
// This method should be called for message fields and in a MapEntry
|
||||
// message only the value field can possibly be a message field.
|
||||
if (field.getNumber() != 2 || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new RuntimeException("\"" + field.getFullName() + "\" is not a message value field.");
|
||||
}
|
||||
return ((Message) value).newBuilderForType();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Builder<K, V> setField(FieldDescriptor field, Object value) {
|
||||
checkFieldDescriptor(field);
|
||||
if (value == null) {
|
||||
throw new NullPointerException(field.getFullName() + " is null");
|
||||
}
|
||||
|
||||
if (field.getNumber() == 1) {
|
||||
setKey((K) value);
|
||||
} else {
|
||||
if (field.getType() == FieldDescriptor.Type.ENUM) {
|
||||
value = ((EnumValueDescriptor) value).getNumber();
|
||||
} else if (field.getType() == FieldDescriptor.Type.MESSAGE) {
|
||||
if (!metadata.defaultValue.getClass().isInstance(value)) {
|
||||
// The value is not the exact right message type. However, if it
|
||||
// is an alternative implementation of the same type -- e.g. a
|
||||
// DynamicMessage -- we should accept it. In this case we can make
|
||||
// a copy of the message.
|
||||
value =
|
||||
((Message) metadata.defaultValue).toBuilder().mergeFrom((Message) value).build();
|
||||
}
|
||||
}
|
||||
setValue((V) value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> clearField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
if (field.getNumber() == 1) {
|
||||
clearKey();
|
||||
} else {
|
||||
clearValue();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> setRepeatedField(FieldDescriptor field, int index, Object value) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> addRepeatedField(FieldDescriptor field, Object value) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> setUnknownFields(UnknownFieldSet unknownFields) {
|
||||
// Unknown fields are discarded for MapEntry message.
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapEntry<K, V> getDefaultInstanceForType() {
|
||||
return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return MapEntry.isInitialized(metadata, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
|
||||
for (final FieldDescriptor field : metadata.descriptor.getFields()) {
|
||||
if (hasField(field)) {
|
||||
result.put(field, getField(field));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
return field.getNumber() == 1 ? hasKey : hasValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
Object result = field.getNumber() == 1 ? getKey() : getValue();
|
||||
// Convert enums to EnumValueDescriptor.
|
||||
if (field.getType() == FieldDescriptor.Type.ENUM) {
|
||||
result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
throw new RuntimeException("There is no repeated field in a map entry message.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<K, V> clone() {
|
||||
return new Builder<>(metadata, key, value, hasKey, hasValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static <V> boolean isInitialized(Metadata metadata, V value) {
|
||||
if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
|
||||
return ((MessageLite) value).isInitialized();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the metadata only for experimental runtime. */
|
||||
final Metadata<K, V> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements the lite version of map entry messages.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <p>Protobuf internal. Users shouldn't use.
|
||||
*/
|
||||
public class MapEntryLite<K, V> {
|
||||
|
||||
static class Metadata<K, V> {
|
||||
public final WireFormat.FieldType keyType;
|
||||
public final K defaultKey;
|
||||
public final WireFormat.FieldType valueType;
|
||||
public final V defaultValue;
|
||||
|
||||
public Metadata(
|
||||
WireFormat.FieldType keyType,
|
||||
K defaultKey,
|
||||
WireFormat.FieldType valueType,
|
||||
V defaultValue) {
|
||||
this.keyType = keyType;
|
||||
this.defaultKey = defaultKey;
|
||||
this.valueType = valueType;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int KEY_FIELD_NUMBER = 1;
|
||||
private static final int VALUE_FIELD_NUMBER = 2;
|
||||
|
||||
private final Metadata<K, V> metadata;
|
||||
private final K key;
|
||||
private final V value;
|
||||
|
||||
/** Creates a default MapEntryLite message instance. */
|
||||
private MapEntryLite(
|
||||
WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue) {
|
||||
this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultValue);
|
||||
this.key = defaultKey;
|
||||
this.value = defaultValue;
|
||||
}
|
||||
|
||||
/** Creates a new MapEntryLite message. */
|
||||
private MapEntryLite(Metadata<K, V> metadata, K key, V value) {
|
||||
this.metadata = metadata;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default MapEntryLite message instance.
|
||||
*
|
||||
* <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);
|
||||
}
|
||||
|
||||
static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata, K key, V value)
|
||||
throws IOException {
|
||||
FieldSet.writeElement(output, metadata.keyType, KEY_FIELD_NUMBER, key);
|
||||
FieldSet.writeElement(output, metadata.valueType, VALUE_FIELD_NUMBER, value);
|
||||
}
|
||||
|
||||
static <K, V> int computeSerializedSize(Metadata<K, V> metadata, K key, V value) {
|
||||
return FieldSet.computeElementSize(metadata.keyType, KEY_FIELD_NUMBER, key)
|
||||
+ FieldSet.computeElementSize(metadata.valueType, VALUE_FIELD_NUMBER, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> T parseField(
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
WireFormat.FieldType type,
|
||||
T value)
|
||||
throws IOException {
|
||||
switch (type) {
|
||||
case MESSAGE:
|
||||
MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder();
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
return (T) subBuilder.buildPartial();
|
||||
case ENUM:
|
||||
return (T) (java.lang.Integer) input.readEnum();
|
||||
case GROUP:
|
||||
throw new RuntimeException("Groups are not allowed in maps.");
|
||||
default:
|
||||
return (T) FieldSet.readPrimitiveField(input, type, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
output.writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
output.writeUInt32NoTag(computeSerializedSize(metadata, key, value));
|
||||
writeTo(output, metadata, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
+ CodedOutputStream.computeLengthDelimitedFieldSize(
|
||||
computeSerializedSize(metadata, key, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
return parseEntry(bytes.newCodedInput(), metadata, extensionRegistry);
|
||||
}
|
||||
|
||||
static <K, V> Map.Entry<K, V> parseEntry(
|
||||
CodedInputStream input, Metadata<K, V> metadata, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
K key = metadata.defaultKey;
|
||||
V value = metadata.defaultValue;
|
||||
while (true) {
|
||||
int tag = input.readTag();
|
||||
if (tag == 0) {
|
||||
break;
|
||||
}
|
||||
if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
|
||||
key = parseField(input, extensionRegistry, metadata.keyType, key);
|
||||
} else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
|
||||
value = parseField(input, extensionRegistry, metadata.valueType, value);
|
||||
} else {
|
||||
if (!input.skipField(tag)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new AbstractMap.SimpleImmutableEntry<K, V>(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an entry off of the input into the map. This helper avoids allocation 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 {
|
||||
int length = input.readRawVarint32();
|
||||
final int oldLimit = input.pushLimit(length);
|
||||
K key = metadata.defaultKey;
|
||||
V value = metadata.defaultValue;
|
||||
|
||||
while (true) {
|
||||
int tag = input.readTag();
|
||||
if (tag == 0) {
|
||||
break;
|
||||
}
|
||||
if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
|
||||
key = parseField(input, extensionRegistry, metadata.keyType, key);
|
||||
} else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
|
||||
value = parseField(input, extensionRegistry, metadata.valueType, value);
|
||||
} else {
|
||||
if (!input.skipField(tag)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.checkLastTagWas(0);
|
||||
input.popLimit(oldLimit);
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
/** For experimental runtime internal use only. */
|
||||
Metadata<K, V> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Internal representation of map fields in generated messages.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <p>This class is a protobuf implementation detail. Users shouldn't use this class directly.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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>
|
||||
*
|
||||
* <p>When the map field is accessed (through generated API or reflection API), it will shift
|
||||
* between these 3 modes:
|
||||
*
|
||||
* <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>
|
||||
*
|
||||
* <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 volatile boolean isMutable;
|
||||
private volatile StorageMode mode;
|
||||
private MutabilityAwareMap<K, V> mapData;
|
||||
private List<Message> listData;
|
||||
|
||||
// Convert between a map entry Message and a key-value pair.
|
||||
private static interface Converter<K, V> {
|
||||
Message convertKeyAndValueToMessage(K key, V value);
|
||||
|
||||
void convertMessageToKeyAndValue(Message message, Map<K, V> map);
|
||||
|
||||
Message getMessageDefaultInstance();
|
||||
}
|
||||
|
||||
private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
|
||||
private final MapEntry<K, V> defaultEntry;
|
||||
|
||||
public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
|
||||
this.defaultEntry = defaultEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message convertKeyAndValueToMessage(K key, V value) {
|
||||
return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
|
||||
MapEntry<K, V> entry = (MapEntry<K, V>) message;
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessageDefaultInstance() {
|
||||
return defaultEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Converter<K, V> converter;
|
||||
|
||||
private MapField(Converter<K, V> converter, StorageMode mode, Map<K, V> mapData) {
|
||||
this.converter = converter;
|
||||
this.isMutable = true;
|
||||
this.mode = mode;
|
||||
this.mapData = new MutabilityAwareMap<K, V>(this, mapData);
|
||||
this.listData = null;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
/** 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>());
|
||||
}
|
||||
|
||||
|
||||
private Message convertKeyAndValueToMessage(K key, V value) {
|
||||
return converter.convertKeyAndValueToMessage(key, value);
|
||||
}
|
||||
|
||||
private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
|
||||
converter.convertMessageToKeyAndValue(message, map);
|
||||
}
|
||||
|
||||
private List<Message> convertMapToList(MutabilityAwareMap<K, V> mapData) {
|
||||
List<Message> listData = new ArrayList<Message>();
|
||||
for (Map.Entry<K, V> entry : mapData.entrySet()) {
|
||||
listData.add(convertKeyAndValueToMessage(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return listData;
|
||||
}
|
||||
|
||||
private MutabilityAwareMap<K, V> convertListToMap(List<Message> listData) {
|
||||
Map<K, V> mapData = new LinkedHashMap<K, V>();
|
||||
for (Message item : listData) {
|
||||
convertMessageToKeyAndValue(item, mapData);
|
||||
}
|
||||
return new MutabilityAwareMap<K, V>(this, mapData);
|
||||
}
|
||||
|
||||
/** Returns the content of this MapField as a read-only Map. */
|
||||
public Map<K, V> getMap() {
|
||||
if (mode == StorageMode.LIST) {
|
||||
synchronized (this) {
|
||||
if (mode == StorageMode.LIST) {
|
||||
mapData = convertListToMap(listData);
|
||||
mode = StorageMode.BOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(mapData);
|
||||
}
|
||||
|
||||
/** Gets a mutable Map view of this MapField. */
|
||||
public Map<K, V> getMutableMap() {
|
||||
if (mode != StorageMode.MAP) {
|
||||
if (mode == StorageMode.LIST) {
|
||||
mapData = convertListToMap(listData);
|
||||
}
|
||||
listData = null;
|
||||
mode = StorageMode.MAP;
|
||||
}
|
||||
return mapData;
|
||||
}
|
||||
|
||||
public void mergeFrom(MapField<K, V> other) {
|
||||
getMutableMap().putAll(MapFieldLite.copy(other.getMap()));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mapData = new MutabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
|
||||
mode = StorageMode.MAP;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (!(object instanceof MapField)) {
|
||||
return false;
|
||||
}
|
||||
MapField<K, V> other = (MapField<K, V>) object;
|
||||
return MapFieldLite.<K, V>equals(getMap(), other.getMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return MapFieldLite.<K, V>calculateHashCodeForMap(getMap());
|
||||
}
|
||||
|
||||
/** Returns a deep copy of this MapField. */
|
||||
public MapField<K, V> copy() {
|
||||
return new MapField<K, V>(converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
|
||||
}
|
||||
|
||||
/** Gets the content of this MapField as a read-only List. */
|
||||
List<Message> getList() {
|
||||
if (mode == StorageMode.MAP) {
|
||||
synchronized (this) {
|
||||
if (mode == StorageMode.MAP) {
|
||||
listData = convertMapToList(mapData);
|
||||
mode = StorageMode.BOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(listData);
|
||||
}
|
||||
|
||||
/** Gets a mutable List view of this MapField. */
|
||||
List<Message> getMutableList() {
|
||||
if (mode != StorageMode.LIST) {
|
||||
if (mode == StorageMode.MAP) {
|
||||
listData = convertMapToList(mapData);
|
||||
}
|
||||
mapData = null;
|
||||
mode = StorageMode.LIST;
|
||||
}
|
||||
return listData;
|
||||
}
|
||||
|
||||
/** Gets the default instance of the message stored in the list view of this map field. */
|
||||
Message getMapEntryMessageDefaultInstance() {
|
||||
return converter.getMessageDefaultInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this list immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
isMutable = false;
|
||||
}
|
||||
|
||||
/** Returns whether this field can be modified. */
|
||||
public boolean isMutable() {
|
||||
return isMutable;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.protobuf.MutabilityOracle#ensureMutable()
|
||||
*/
|
||||
@Override
|
||||
public void ensureMutable() {
|
||||
if (!isMutable()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/** An internal map that checks for mutability before delegating. */
|
||||
private static class MutabilityAwareMap<K, V> implements Map<K, V> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Map<K, V> delegate;
|
||||
|
||||
MutabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
|
||||
this.mutabilityOracle = mutabilityOracle;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return delegate.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return delegate.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return delegate.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
checkNotNull(key);
|
||||
checkNotNull(value);
|
||||
return delegate.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
for (K key : m.keySet()) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(m.get(key));
|
||||
}
|
||||
delegate.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mutabilityOracle.ensureMutable();
|
||||
delegate.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return new MutabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return new MutabilityAwareCollection<V>(mutabilityOracle, delegate.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
return new MutabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return delegate.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
/** An internal collection that checks for mutability before delegating. */
|
||||
private static class MutabilityAwareCollection<E> implements Collection<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Collection<E> delegate;
|
||||
|
||||
MutabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
|
||||
this.mutabilityOracle = mutabilityOracle;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return delegate.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new MutabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return delegate.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return delegate.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
// Unsupported operation in the delegate.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return delegate.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
// Unsupported operation in the delegate.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mutabilityOracle.ensureMutable();
|
||||
delegate.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return delegate.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** An internal set that checks for mutability before delegating. */
|
||||
private static class MutabilityAwareSet<E> implements Set<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Set<E> delegate;
|
||||
|
||||
MutabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
|
||||
this.mutabilityOracle = mutabilityOracle;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return delegate.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new MutabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return delegate.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return delegate.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return delegate.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
return delegate.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mutabilityOracle.ensureMutable();
|
||||
delegate.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return delegate.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** An internal iterator that checks for mutability before delegating. */
|
||||
private static class MutabilityAwareIterator<E> implements Iterator<E> {
|
||||
private final MutabilityOracle mutabilityOracle;
|
||||
private final Iterator<E> delegate;
|
||||
|
||||
MutabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
|
||||
this.mutabilityOracle = mutabilityOracle;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return delegate.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
return delegate.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
mutabilityOracle.ensureMutable();
|
||||
delegate.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.EnumLite;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Internal representation of map fields in generated lite-runtime messages.
|
||||
*
|
||||
* <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> {
|
||||
|
||||
private boolean isMutable;
|
||||
|
||||
private MapFieldLite() {
|
||||
this.isMutable = true;
|
||||
}
|
||||
|
||||
private MapFieldLite(Map<K, V> mapData) {
|
||||
super(mapData);
|
||||
this.isMutable = true;
|
||||
}
|
||||
|
||||
private static final MapFieldLite<?, ?> EMPTY_MAP_FIELD = new MapFieldLite<>();
|
||||
|
||||
static {
|
||||
EMPTY_MAP_FIELD.makeImmutable();
|
||||
}
|
||||
|
||||
/** Returns a singleton immutable empty MapFieldLite instance. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K, V> MapFieldLite<K, V> emptyMapField() {
|
||||
return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
|
||||
}
|
||||
|
||||
public void mergeFrom(MapFieldLite<K, V> other) {
|
||||
ensureMutable();
|
||||
if (!other.isEmpty()) {
|
||||
putAll(other);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
ensureMutable();
|
||||
super.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
ensureMutable();
|
||||
checkNotNull(key);
|
||||
|
||||
checkNotNull(value);
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
public V put(Map.Entry<K, V> entry) {
|
||||
return put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
ensureMutable();
|
||||
checkForNullKeysAndValues(m);
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
ensureMutable();
|
||||
return super.remove(key);
|
||||
}
|
||||
|
||||
private static void checkForNullKeysAndValues(Map<?, ?> m) {
|
||||
for (Object key : m.keySet()) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(m.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equals(Object a, Object b) {
|
||||
if (a instanceof byte[] && b instanceof byte[]) {
|
||||
return Arrays.equals((byte[]) a, (byte[]) b);
|
||||
}
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two {@link Map}s are equal. We don't use the default equals method of {@link
|
||||
* Map} because it compares by identity not by content for byte arrays.
|
||||
*/
|
||||
static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<K, V> entry : a.entrySet()) {
|
||||
if (!b.containsKey(entry.getKey())) {
|
||||
return false;
|
||||
}
|
||||
if (!equals(entry.getValue(), b.get(entry.getKey()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Checks whether two map fields are equal. */
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return (object instanceof Map) && equals(this, (Map<K, V>) object);
|
||||
}
|
||||
|
||||
private static int calculateHashCodeForObject(Object a) {
|
||||
if (a instanceof byte[]) {
|
||||
return Internal.hashCode((byte[]) a);
|
||||
}
|
||||
// Enums should be stored as integers internally.
|
||||
if (a instanceof EnumLite) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return a.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash code for a {@link Map}. We don't use the default hash code method of {@link
|
||||
* Map} because for byte arrays and protobuf enums it use {@link Object#hashCode()}.
|
||||
*/
|
||||
static <K, V> int calculateHashCodeForMap(Map<K, V> a) {
|
||||
int result = 0;
|
||||
for (Map.Entry<K, V> entry : a.entrySet()) {
|
||||
result +=
|
||||
calculateHashCodeForObject(entry.getKey()) ^ calculateHashCodeForObject(entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return calculateHashCodeForMap(this);
|
||||
}
|
||||
|
||||
private static Object copy(Object object) {
|
||||
if (object instanceof byte[]) {
|
||||
byte[] data = (byte[]) object;
|
||||
return Arrays.copyOf(data, data.length);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a deep copy of a {@link Map}. Immutable objects in the map will be shared (e.g.,
|
||||
* integers, strings, immutable messages) and mutable ones will have a copy (e.g., byte arrays,
|
||||
* mutable messages).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K, V> Map<K, V> copy(Map<K, V> map) {
|
||||
Map<K, V> result = new LinkedHashMap<K, V>();
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
result.put(entry.getKey(), (V) copy(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns a deep copy of this map field. */
|
||||
public MapFieldLite<K, V> mutableCopy() {
|
||||
return isEmpty() ? new MapFieldLite<K, V>() : new MapFieldLite<K, V>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this field immutable. All subsequent modifications will throw an {@link
|
||||
* UnsupportedOperationException}.
|
||||
*/
|
||||
public void makeImmutable() {
|
||||
isMutable = false;
|
||||
}
|
||||
|
||||
/** Returns whether this field can be modified. */
|
||||
public boolean isMutable() {
|
||||
return isMutable;
|
||||
}
|
||||
|
||||
private void ensureMutable() {
|
||||
if (!isMutable()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@CheckReturnValue
|
||||
interface MapFieldSchema {
|
||||
/** Returns the map data for mutation. */
|
||||
Map<?, ?> forMutableMapData(Object mapField);
|
||||
|
||||
/** Returns the map data for read. */
|
||||
Map<?, ?> forMapData(Object mapField);
|
||||
|
||||
/** Whether toImmutable() has been called on this map field. */
|
||||
boolean isImmutable(Object mapField);
|
||||
|
||||
/**
|
||||
* Returns an immutable instance of the map field. It may make the parameter immutable and return
|
||||
* the parameter, or create an immutable copy. The status of the parameter after the call is
|
||||
* undefined.
|
||||
*/
|
||||
Object toImmutable(Object mapField);
|
||||
|
||||
/** Returns a new instance of the map field given a map default entry. */
|
||||
Object newMapField(Object mapDefaultEntry);
|
||||
|
||||
/** Returns the metadata from a default entry. */
|
||||
MapEntryLite.Metadata<?, ?> forMapMetadata(Object mapDefaultEntry);
|
||||
|
||||
/** Merges {@code srcMapField} into {@code destMapField}, and returns the merged instance. */
|
||||
@CanIgnoreReturnValue
|
||||
Object mergeFrom(Object destMapField, Object srcMapField);
|
||||
|
||||
/** Compute the serialized size for the map with a given field number. */
|
||||
int getSerializedSize(int fieldNumber, Object mapField, Object mapDefaultEntry);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.MapEntryLite.Metadata;
|
||||
import java.util.Map;
|
||||
|
||||
class MapFieldSchemaFull implements MapFieldSchema {
|
||||
@Override
|
||||
public Map<?, ?> forMutableMapData(Object mapField) {
|
||||
return ((MapField<?, ?>) mapField).getMutableMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> forMapData(Object mapField) {
|
||||
return ((MapField<?, ?>) mapField).getMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmutable(Object mapField) {
|
||||
return !((MapField<?, ?>) mapField).isMutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toImmutable(Object mapField) {
|
||||
((MapField<?, ?>) mapField).makeImmutable();
|
||||
return mapField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newMapField(Object mapDefaultEntry) {
|
||||
return MapField.newMapField((MapEntry<?, ?>) mapDefaultEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata<?, ?> forMapMetadata(Object mapDefaultEntry) {
|
||||
return ((MapEntry<?, ?>) mapDefaultEntry).getMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mergeFrom(Object destMapField, Object srcMapField) {
|
||||
return mergeFromFull(destMapField, srcMapField);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <K, V> Object mergeFromFull(Object destMapField, Object srcMapField) {
|
||||
MapField<K, V> mine = (MapField<K, V>) destMapField;
|
||||
MapField<K, V> other = (MapField<K, V>) srcMapField;
|
||||
if (!mine.isMutable()) {
|
||||
mine.copy();
|
||||
}
|
||||
mine.mergeFrom(other);
|
||||
return mine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize(int number, Object mapField, Object mapDefaultEntry) {
|
||||
return getSerializedSizeFull(number, mapField, mapDefaultEntry);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <K, V> int getSerializedSizeFull(
|
||||
int number, Object mapField, Object defaultEntryObject) {
|
||||
// Full runtime allocates map fields lazily.
|
||||
if (mapField == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Map<K, V> map = ((MapField<K, V>) mapField).getMap();
|
||||
MapEntry<K, V> defaultEntry = (MapEntry<K, V>) defaultEntryObject;
|
||||
if (map.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int size = 0;
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
size +=
|
||||
CodedOutputStream.computeTagSize(number)
|
||||
+ CodedOutputStream.computeLengthDelimitedFieldSize(
|
||||
MapEntryLite.computeSerializedSize(
|
||||
defaultEntry.getMetadata(), entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.MapEntryLite.Metadata;
|
||||
import java.util.Map;
|
||||
|
||||
@CheckReturnValue
|
||||
class MapFieldSchemaLite implements MapFieldSchema {
|
||||
|
||||
@Override
|
||||
public Map<?, ?> forMutableMapData(Object mapField) {
|
||||
return (MapFieldLite<?, ?>) mapField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata<?, ?> forMapMetadata(Object mapDefaultEntry) {
|
||||
return ((MapEntryLite<?, ?>) mapDefaultEntry).getMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> forMapData(Object mapField) {
|
||||
return (MapFieldLite<?, ?>) mapField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmutable(Object mapField) {
|
||||
return !((MapFieldLite<?, ?>) mapField).isMutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toImmutable(Object mapField) {
|
||||
((MapFieldLite<?, ?>) mapField).makeImmutable();
|
||||
return mapField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newMapField(Object unused) {
|
||||
return MapFieldLite.emptyMapField().mutableCopy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mergeFrom(Object destMapField, Object srcMapField) {
|
||||
return mergeFromLite(destMapField, srcMapField);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <K, V> MapFieldLite<K, V> mergeFromLite(Object destMapField, Object srcMapField) {
|
||||
MapFieldLite<K, V> mine = (MapFieldLite<K, V>) destMapField;
|
||||
MapFieldLite<K, V> other = (MapFieldLite<K, V>) srcMapField;
|
||||
if (!other.isEmpty()) {
|
||||
if (!mine.isMutable()) {
|
||||
mine = mine.mutableCopy();
|
||||
}
|
||||
mine.mergeFrom(other);
|
||||
}
|
||||
return mine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize(int fieldNumber, Object mapField, Object mapDefaultEntry) {
|
||||
return getSerializedSizeLite(fieldNumber, mapField, mapDefaultEntry);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <K, V> int getSerializedSizeLite(
|
||||
int fieldNumber, Object mapField, Object defaultEntry) {
|
||||
MapFieldLite<K, V> mapFieldLite = (MapFieldLite<K, V>) mapField;
|
||||
MapEntryLite<K, V> defaultEntryLite = (MapEntryLite<K, V>) defaultEntry;
|
||||
|
||||
if (mapFieldLite.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int size = 0;
|
||||
for (Map.Entry<K, V> entry : mapFieldLite.entrySet()) {
|
||||
size += defaultEntryLite.computeMessageSize(fieldNumber, entry.getKey(), entry.getValue());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
@CheckReturnValue
|
||||
final class MapFieldSchemas {
|
||||
private static final MapFieldSchema FULL_SCHEMA = loadSchemaForFullRuntime();
|
||||
private static final MapFieldSchema LITE_SCHEMA = new MapFieldSchemaLite();
|
||||
|
||||
static MapFieldSchema full() {
|
||||
return FULL_SCHEMA;
|
||||
}
|
||||
|
||||
static MapFieldSchema lite() {
|
||||
return LITE_SCHEMA;
|
||||
}
|
||||
|
||||
private static MapFieldSchema loadSchemaForFullRuntime() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.google.protobuf.MapFieldSchemaFull");
|
||||
return (MapFieldSchema) clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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 methods that are not available in the "lite" runtime. The biggest added
|
||||
* features are introspection and reflection; that is, getting descriptors for the message type and
|
||||
* accessing the field values dynamically.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public interface Message extends MessageLite, MessageOrBuilder {
|
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
@Override
|
||||
Parser<? extends Message> getParserForType();
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// 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.
|
||||
*
|
||||
* @param other object to be compared for equality with this message
|
||||
* @return {@code true} if the specified object is equal to this message
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*
|
||||
* @return the hash code value for this message
|
||||
* @see Map#hashCode()
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Converts the message to a string in protocol buffer text format. This is just a trivial wrapper
|
||||
* around {@link TextFormat.Printer#printToString(MessageOrBuilder)}.
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
// =================================================================
|
||||
// Builders
|
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
@Override
|
||||
Builder newBuilderForType();
|
||||
|
||||
@Override
|
||||
Builder toBuilder();
|
||||
|
||||
/** Abstract interface implemented by Protocol Message builders. */
|
||||
interface Builder extends MessageLite.Builder, MessageOrBuilder {
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
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()}).
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <p>This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(Message other);
|
||||
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
Message build();
|
||||
|
||||
@Override
|
||||
Message buildPartial();
|
||||
|
||||
@Override
|
||||
Builder clone();
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(CodedInputStream input) throws IOException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/** 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. The
|
||||
* builder is NOT nested in the current builder. However, messages built with the
|
||||
* builder can then be passed to the {@link #setField(Descriptors.FieldDescriptor, Object)},
|
||||
* {@link #setRepeatedField(Descriptors.FieldDescriptor, int, Object)}, or
|
||||
* {@link #addRepeatedField(Descriptors.FieldDescriptor, Object)}
|
||||
* method of the current builder.
|
||||
*
|
||||
* <p>To obtain a builder nested in the current builder, use
|
||||
* {@link #getFieldBuilder(Descriptors.FieldDescriptor)} instead.
|
||||
*/
|
||||
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) 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 is
|
||||
* returned. Otherwise, a new field builder is created and returned. The original message
|
||||
* field (if one exists) is merged into the field builder, which is then nested into its
|
||||
* parent builder.
|
||||
*/
|
||||
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) 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 is
|
||||
* returned. Otherwise, a new field builder is created and returned. The original message
|
||||
* field (if one exists) is merged into the field builder, which is then nested into its
|
||||
* parent builder.
|
||||
*/
|
||||
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, that
|
||||
* is, the same type that {@link Message#getField(Descriptors.FieldDescriptor)} returns.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
Builder clearField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Clears the oneof. This is exactly equivalent to calling the generated "clear" accessor method
|
||||
* corresponding to the oneof.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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; that is, the same type that {@link
|
||||
* Message#getRepeatedField(Descriptors.FieldDescriptor,int)} returns.
|
||||
*
|
||||
* @throws IllegalArgumentException if the field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
|
||||
|
||||
/**
|
||||
* Like {@code setRepeatedField}, but appends the value as a new element.
|
||||
*
|
||||
* @throws IllegalArgumentException if the field is not a repeated field, or {@code
|
||||
* field.getContainingType() != getDescriptorForType()}
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/** Set the {@link UnknownFieldSet} for this message. */
|
||||
@CanIgnoreReturnValue
|
||||
Builder setUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
/** Merge some unknown fields into the {@link UnknownFieldSet} for this message. */
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(InputStream input) throws IOException;
|
||||
|
||||
@Override
|
||||
@CanIgnoreReturnValue
|
||||
Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
boolean mergeDelimitedFrom(InputStream input) throws IOException;
|
||||
|
||||
@Override
|
||||
boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** A MessageInfo object describes a proto message type. */
|
||||
@CheckReturnValue
|
||||
interface MessageInfo {
|
||||
/** Gets syntax for this type. */
|
||||
ProtoSyntax getSyntax();
|
||||
|
||||
/** Whether this type is MessageSet. */
|
||||
boolean isMessageSetWireFormat();
|
||||
|
||||
/** Gets the default instance of this type. */
|
||||
MessageLite getDefaultInstance();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** A factory that creates {@link MessageInfo} instances for message types. */
|
||||
@ExperimentalApi
|
||||
@CheckReturnValue
|
||||
interface MessageInfoFactory {
|
||||
/** Whether the message class is supported by this factory. */
|
||||
boolean isSupported(Class<?> clazz);
|
||||
|
||||
/** Returns a information of the message class. */
|
||||
MessageInfo messageInfoFor(Class<?> clazz);
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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:
|
||||
*
|
||||
* <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>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
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public interface MessageLite extends MessageLiteOrBuilder {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* If this message requires more than Integer.MAX_VALUE bytes to encode, the return value will
|
||||
* be smaller than the actual number of bytes required and might be negative.
|
||||
*/
|
||||
int getSerializedSize();
|
||||
|
||||
/** 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)}.
|
||||
*
|
||||
* If this message requires more than Integer.MAX_VALUE bytes to encode, the behavior is
|
||||
* unpredictable. It may throw a runtime exception or truncate or slice the data.
|
||||
*/
|
||||
ByteString toByteString();
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code byte} array and returns it. This is just a trivial wrapper
|
||||
* around {@link #writeTo(CodedOutputStream)}.
|
||||
*
|
||||
* If this message requires more than Integer.MAX_VALUE bytes to encode, the behavior is
|
||||
* unpredictable. It may throw a runtime exception or truncate or slice the data.
|
||||
*/
|
||||
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, for instance, by
|
||||
* writing the size of the message before the data, then making sure to limit the input to that
|
||||
* size on the receiving end 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.
|
||||
*/
|
||||
void writeDelimitedTo(OutputStream output) throws IOException;
|
||||
|
||||
|
||||
// =================================================================
|
||||
// Builders
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
Builder toBuilder();
|
||||
|
||||
/** Abstract interface implemented by Protocol Message builders. */
|
||||
interface Builder extends MessageLiteOrBuilder, Cloneable {
|
||||
/** Resets all fields to their default values. */
|
||||
@CanIgnoreReturnValue
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <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.
|
||||
* </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.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes read are not syntactically correct according
|
||||
* to the protobuf wire format specification. The data is corrupt, incomplete, or was never
|
||||
* a protobuf in the first place.
|
||||
* @throws IOException an I/O error reading from the stream
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes read are not syntactically correct according
|
||||
* to the protobuf wire format specification. The data is corrupt, incomplete, or was never
|
||||
* a protobuf in the first place.
|
||||
* @throws IOException an I/O error reading from the stream
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
|
||||
* according to the protobuf wire format specification. The data is corrupt, incomplete, or
|
||||
* was never a protobuf in the first place.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException the bytes read are not syntactically correct according
|
||||
* to the protobuf wire format specification. The data is corrupt, incomplete, or was never
|
||||
* a protobuf in the first place.
|
||||
* @throws IOException an I/O error reading from the stream
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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)}.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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())}).
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <p>This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
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.
|
||||
*
|
||||
* @return true if successful, or false if the stream is at EOF when the method starts. Any
|
||||
* other error (including reaching EOF during parsing) causes an exception to be thrown.
|
||||
* @throws InvalidProtocolBufferException the bytes read are not syntactically correct according
|
||||
* to the protobuf wire format specification. The data is corrupt, incomplete, or was never
|
||||
* a protobuf in the first place.
|
||||
* @throws IOException an I/O error reading from the stream
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
|
||||
*
|
||||
* @return true if successful, or false if the stream is at EOF when the method starts. Any
|
||||
* other error (including reaching EOF during parsing) causes an exception to be thrown.
|
||||
* @throws InvalidProtocolBufferException the bytes read are not syntactically correct according
|
||||
* to the protobuf wire format specification. The data is corrupt, incomplete, or was never
|
||||
* a protobuf in the first place.
|
||||
* @throws IOException an I/O error reading from the stream
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Base interface for methods common to {@link MessageLite} and {@link MessageLite.Builder} to
|
||||
* provide type equivalency.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@CheckReturnValue
|
||||
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.
|
||||
*/
|
||||
MessageLite getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/** Helps generate {@link String} representations of {@link MessageLite} protos. */
|
||||
final class MessageLiteToString {
|
||||
|
||||
private static final String LIST_SUFFIX = "List";
|
||||
private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
|
||||
private static final String MAP_SUFFIX = "Map";
|
||||
private static final String BYTES_SUFFIX = "Bytes";
|
||||
private static final char[] INDENT_BUFFER = new char[80];
|
||||
|
||||
static {
|
||||
Arrays.fill(INDENT_BUFFER, ' ');
|
||||
}
|
||||
|
||||
private MessageLiteToString() {
|
||||
// Classes which are not intended to be instantiated should be made non-instantiable with a
|
||||
// private constructor. This includes utility classes (classes with only static members).
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} representation of the {@link MessageLite} object. The first line of
|
||||
* the {@code String} representation includes a comment string to uniquely identify
|
||||
* the object instance. This acts as an indicator that this should not be relied on for
|
||||
* comparisons.
|
||||
*/
|
||||
static String toString(MessageLite messageLite, String commentString) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("# ").append(commentString);
|
||||
reflectivePrintWithIndent(messageLite, buffer, 0);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level.
|
||||
*
|
||||
* @param buffer the buffer to write to
|
||||
* @param indent the number of spaces to indent the proto by
|
||||
*/
|
||||
private static void reflectivePrintWithIndent(
|
||||
MessageLite messageLite, StringBuilder buffer, int indent) {
|
||||
// Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
|
||||
// getFooList() and getFooMap() which might be useful for building an object's string
|
||||
// representation.
|
||||
Set<String> setters = new HashSet<>();
|
||||
Map<String, Method> hazzers = new HashMap<>();
|
||||
Map<String, Method> getters = new TreeMap<>();
|
||||
for (Method method : messageLite.getClass().getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (method.getName().length() < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getName().startsWith("set")) {
|
||||
setters.add(method.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getParameterTypes().length != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getName().startsWith("has")) {
|
||||
hazzers.put(method.getName(), method);
|
||||
} else if (method.getName().startsWith("get")) {
|
||||
getters.put(method.getName(), method);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<String, Method> getter : getters.entrySet()) {
|
||||
String suffix = getter.getKey().substring(3);
|
||||
if (suffix.endsWith(LIST_SUFFIX)
|
||||
&& !suffix.endsWith(BUILDER_LIST_SUFFIX)
|
||||
// Sometimes people have fields named 'list' that aren't repeated.
|
||||
&& !suffix.equals(LIST_SUFFIX)) {
|
||||
// Try to reflectively get the value and toString() the field as if it were repeated. This
|
||||
// only works if the method names have not been proguarded out or renamed.
|
||||
Method listMethod = getter.getValue();
|
||||
if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
|
||||
printField(
|
||||
buffer,
|
||||
indent,
|
||||
suffix.substring(0, suffix.length() - LIST_SUFFIX.length()),
|
||||
GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (suffix.endsWith(MAP_SUFFIX)
|
||||
// Sometimes people have fields named 'map' that aren't maps.
|
||||
&& !suffix.equals(MAP_SUFFIX)) {
|
||||
// Try to reflectively get the value and toString() the field as if it were a map. This only
|
||||
// works if the method names have not been proguarded out or renamed.
|
||||
Method mapMethod = getter.getValue();
|
||||
if (mapMethod != null
|
||||
&& mapMethod.getReturnType().equals(Map.class)
|
||||
// Skip the deprecated getter method with no prefix "Map" when the field name ends with
|
||||
// "map".
|
||||
&& !mapMethod.isAnnotationPresent(Deprecated.class)
|
||||
// Skip the internal mutable getter method.
|
||||
&& Modifier.isPublic(mapMethod.getModifiers())) {
|
||||
printField(
|
||||
buffer,
|
||||
indent,
|
||||
suffix.substring(0, suffix.length() - MAP_SUFFIX.length()),
|
||||
GeneratedMessageLite.invokeOrDie(mapMethod, messageLite));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!setters.contains("set" + suffix)) {
|
||||
continue;
|
||||
}
|
||||
if (suffix.endsWith(BYTES_SUFFIX)
|
||||
&& getters.containsKey("get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
|
||||
// Heuristic to skip bytes based accessors for string fields.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to reflectively get the value and toString() the field as if it were optional. This
|
||||
// only works if the method names have not been proguarded out or renamed.
|
||||
Method getMethod = getter.getValue();
|
||||
Method hasMethod = hazzers.get("has" + suffix);
|
||||
// TODO(dweis): Fix proto3 semantics.
|
||||
if (getMethod != null) {
|
||||
Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
|
||||
final boolean hasValue =
|
||||
hasMethod == null
|
||||
? !isDefaultValue(value)
|
||||
: (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
|
||||
// TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
|
||||
if (hasValue) {
|
||||
printField(buffer, indent, suffix, value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
|
||||
Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
|
||||
((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
|
||||
printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (((GeneratedMessageLite<?, ?>) messageLite).unknownFields != null) {
|
||||
((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDefaultValue(Object o) {
|
||||
if (o instanceof Boolean) {
|
||||
return !((Boolean) o);
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o) == 0;
|
||||
}
|
||||
if (o instanceof Float) {
|
||||
return Float.floatToRawIntBits((Float) o) == 0;
|
||||
}
|
||||
if (o instanceof Double) {
|
||||
return Double.doubleToRawLongBits((Double) o) == 0;
|
||||
}
|
||||
if (o instanceof String) {
|
||||
return o.equals("");
|
||||
}
|
||||
if (o instanceof ByteString) {
|
||||
return o.equals(ByteString.EMPTY);
|
||||
}
|
||||
if (o instanceof MessageLite) { // Can happen in oneofs.
|
||||
return o == ((MessageLite) o).getDefaultInstanceForType();
|
||||
}
|
||||
if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
|
||||
return ((java.lang.Enum<?>) o).ordinal() == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a text proto field.
|
||||
*
|
||||
* <p>For use by generated code only.
|
||||
*
|
||||
* @param buffer the buffer to write to
|
||||
* @param indent the number of spaces the proto should be indented by
|
||||
* @param name the field name (in PascalCase)
|
||||
* @param object the object value of the field
|
||||
*/
|
||||
static void printField(StringBuilder buffer, int indent, String name, Object object) {
|
||||
if (object instanceof List<?>) {
|
||||
List<?> list = (List<?>) object;
|
||||
for (Object entry : list) {
|
||||
printField(buffer, indent, name, entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (object instanceof Map<?, ?>) {
|
||||
Map<?, ?> map = (Map<?, ?>) object;
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
printField(buffer, indent, name, entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.append('\n');
|
||||
indent(indent, buffer);
|
||||
buffer.append(pascalCaseToSnakeCase(name));
|
||||
|
||||
if (object instanceof String) {
|
||||
buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
|
||||
} else if (object instanceof ByteString) {
|
||||
buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"');
|
||||
} else if (object instanceof GeneratedMessageLite) {
|
||||
buffer.append(" {");
|
||||
reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
|
||||
buffer.append("\n");
|
||||
indent(indent, buffer);
|
||||
buffer.append("}");
|
||||
} else if (object instanceof Map.Entry<?, ?>) {
|
||||
buffer.append(" {");
|
||||
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
|
||||
printField(buffer, indent + 2, "key", entry.getKey());
|
||||
printField(buffer, indent + 2, "value", entry.getValue());
|
||||
buffer.append("\n");
|
||||
indent(indent, buffer);
|
||||
buffer.append("}");
|
||||
} else {
|
||||
buffer.append(": ").append(object);
|
||||
}
|
||||
}
|
||||
|
||||
private static void indent(int indent, StringBuilder buffer) {
|
||||
while (indent > 0) {
|
||||
int partialIndent = indent;
|
||||
if (partialIndent > INDENT_BUFFER.length) {
|
||||
partialIndent = INDENT_BUFFER.length;
|
||||
}
|
||||
buffer.append(INDENT_BUFFER, 0, partialIndent);
|
||||
indent -= partialIndent;
|
||||
}
|
||||
}
|
||||
|
||||
private static String pascalCaseToSnakeCase(String pascalCase) {
|
||||
if (pascalCase.isEmpty()) {
|
||||
return pascalCase;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(Character.toLowerCase(pascalCase.charAt(0)));
|
||||
for (int i = 1; i < pascalCase.length(); i++) {
|
||||
char ch = pascalCase.charAt(i);
|
||||
if (Character.isUpperCase(ch)) {
|
||||
builder.append("_");
|
||||
}
|
||||
builder.append(Character.toLowerCase(ch));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base interface for methods common to {@link Message} and {@link Message.Builder} to provide type
|
||||
* equivalency.
|
||||
*
|
||||
* @author jonp@google.com (Jon Perlow)
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public interface MessageOrBuilder extends MessageLiteOrBuilder {
|
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
Map<Descriptors.FieldDescriptor, Object> getAllFields();
|
||||
|
||||
/**
|
||||
* Returns true if the given oneof is set.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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()}.
|
||||
*/
|
||||
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()}.
|
||||
*/
|
||||
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
|
||||
|
||||
/** Get the {@link UnknownFieldSet} for this message. */
|
||||
UnknownFieldSet getUnknownFields();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/** Schema used for proto2 messages using message_set_wireformat. */
|
||||
@CheckReturnValue
|
||||
final class MessageSetSchema<T> implements Schema<T> {
|
||||
private final MessageLite defaultInstance;
|
||||
private final UnknownFieldSchema<?, ?> unknownFieldSchema;
|
||||
private final boolean hasExtensions;
|
||||
private final ExtensionSchema<?> extensionSchema;
|
||||
|
||||
private MessageSetSchema(
|
||||
UnknownFieldSchema<?, ?> unknownFieldSchema,
|
||||
ExtensionSchema<?> extensionSchema,
|
||||
MessageLite defaultInstance) {
|
||||
this.unknownFieldSchema = unknownFieldSchema;
|
||||
this.hasExtensions = extensionSchema.hasExtensions(defaultInstance);
|
||||
this.extensionSchema = extensionSchema;
|
||||
this.defaultInstance = defaultInstance;
|
||||
}
|
||||
|
||||
static <T> MessageSetSchema<T> newSchema(
|
||||
UnknownFieldSchema<?, ?> unknownFieldSchema,
|
||||
ExtensionSchema<?> extensionSchema,
|
||||
MessageLite defaultInstance) {
|
||||
return new MessageSetSchema<T>(unknownFieldSchema, extensionSchema, defaultInstance);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T newInstance() {
|
||||
// TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
||||
// better.
|
||||
if (defaultInstance instanceof GeneratedMessageLite) {
|
||||
return (T) ((GeneratedMessageLite<?, ?>) defaultInstance).newMutableInstance();
|
||||
} else {
|
||||
return (T) defaultInstance.newBuilderForType().buildPartial();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(T message, T other) {
|
||||
Object messageUnknown = unknownFieldSchema.getFromMessage(message);
|
||||
Object otherUnknown = unknownFieldSchema.getFromMessage(other);
|
||||
if (!messageUnknown.equals(otherUnknown)) {
|
||||
return false;
|
||||
}
|
||||
if (hasExtensions) {
|
||||
FieldSet<?> messageExtensions = extensionSchema.getExtensions(message);
|
||||
FieldSet<?> otherExtensions = extensionSchema.getExtensions(other);
|
||||
return messageExtensions.equals(otherExtensions);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(T message) {
|
||||
int hashCode = unknownFieldSchema.getFromMessage(message).hashCode();
|
||||
if (hasExtensions) {
|
||||
FieldSet<?> extensions = extensionSchema.getExtensions(message);
|
||||
hashCode = (hashCode * 53) + extensions.hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeFrom(T message, T other) {
|
||||
SchemaUtil.mergeUnknownFields(unknownFieldSchema, message, other);
|
||||
if (hasExtensions) {
|
||||
SchemaUtil.mergeExtensions(extensionSchema, message, other);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void writeTo(T message, Writer writer) throws IOException {
|
||||
FieldSet<?> extensions = extensionSchema.getExtensions(message);
|
||||
Iterator<?> iterator = extensions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<?, ?> extension = (Entry<?, ?>) iterator.next();
|
||||
FieldSet.FieldDescriptorLite<?> fd = (FieldSet.FieldDescriptorLite<?>) extension.getKey();
|
||||
if (fd.getLiteJavaType() != WireFormat.JavaType.MESSAGE || fd.isRepeated() || fd.isPacked()) {
|
||||
throw new IllegalStateException("Found invalid MessageSet item.");
|
||||
}
|
||||
if (extension instanceof LazyField.LazyEntry) {
|
||||
writer.writeMessageSetItem(
|
||||
fd.getNumber(), ((LazyField.LazyEntry) extension).getField().toByteString());
|
||||
} else {
|
||||
writer.writeMessageSetItem(fd.getNumber(), extension.getValue());
|
||||
}
|
||||
}
|
||||
writeUnknownFieldsHelper(unknownFieldSchema, message, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for wildcard capture of {@code unknownFieldSchema}. See:
|
||||
* https://docs.oracle.com/javase/tutorial/java/generics/capture.html
|
||||
*/
|
||||
private <UT, UB> void writeUnknownFieldsHelper(
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema, T message, Writer writer) throws IOException {
|
||||
unknownFieldSchema.writeAsMessageSetTo(unknownFieldSchema.getFromMessage(message), writer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
@Override
|
||||
public void mergeFrom(
|
||||
T message, byte[] data, int position, int limit, ArrayDecoders.Registers registers)
|
||||
throws IOException {
|
||||
// TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
||||
// better.
|
||||
UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
|
||||
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
|
||||
unknownFields = UnknownFieldSetLite.newInstance();
|
||||
((GeneratedMessageLite) message).unknownFields = unknownFields;
|
||||
}
|
||||
final FieldSet<GeneratedMessageLite.ExtensionDescriptor> extensions =
|
||||
((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable();
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?> extension = null;
|
||||
while (position < limit) {
|
||||
position = ArrayDecoders.decodeVarint32(data, position, registers);
|
||||
final int startTag = registers.int1;
|
||||
if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) {
|
||||
if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
||||
extension =
|
||||
(GeneratedMessageLite.GeneratedExtension<?, ?>) extensionSchema.findExtensionByNumber(
|
||||
registers.extensionRegistry, defaultInstance,
|
||||
WireFormat.getTagFieldNumber(startTag));
|
||||
if (extension != null) {
|
||||
position =
|
||||
ArrayDecoders.decodeMessageField(
|
||||
Protobuf.getInstance().schemaFor(
|
||||
extension.getMessageDefaultInstance().getClass()),
|
||||
data, position, limit, registers);
|
||||
extensions.setField(extension.descriptor, registers.object1);
|
||||
} else {
|
||||
position =
|
||||
ArrayDecoders.decodeUnknownField(
|
||||
startTag, data, position, limit, unknownFields, registers);
|
||||
}
|
||||
} else {
|
||||
position = ArrayDecoders.skipField(startTag, data, position, limit, registers);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int typeId = 0;
|
||||
ByteString rawBytes = null;
|
||||
|
||||
while (position < limit) {
|
||||
position = ArrayDecoders.decodeVarint32(data, position, registers);
|
||||
final int tag = registers.int1;
|
||||
final int number = WireFormat.getTagFieldNumber(tag);
|
||||
final int wireType = WireFormat.getTagWireType(tag);
|
||||
switch (number) {
|
||||
case WireFormat.MESSAGE_SET_TYPE_ID:
|
||||
if (wireType == WireFormat.WIRETYPE_VARINT) {
|
||||
position = ArrayDecoders.decodeVarint32(data, position, registers);
|
||||
typeId = registers.int1;
|
||||
// TODO(b/248560713) decide if we're keeping support for Full in schema classes and
|
||||
// handle this better.
|
||||
extension =
|
||||
(GeneratedMessageLite.GeneratedExtension<?, ?>)
|
||||
extensionSchema.findExtensionByNumber(
|
||||
registers.extensionRegistry, defaultInstance, typeId);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case WireFormat.MESSAGE_SET_MESSAGE:
|
||||
if (extension != null) {
|
||||
position = ArrayDecoders.decodeMessageField(
|
||||
Protobuf.getInstance().schemaFor(
|
||||
extension.getMessageDefaultInstance().getClass()),
|
||||
data, position, limit, registers);
|
||||
extensions.setField(extension.descriptor, registers.object1);
|
||||
continue;
|
||||
} else {
|
||||
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
||||
position = ArrayDecoders.decodeBytes(data, position, registers);
|
||||
rawBytes = (ByteString) registers.object1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (tag == WireFormat.MESSAGE_SET_ITEM_END_TAG) {
|
||||
break;
|
||||
}
|
||||
position = ArrayDecoders.skipField(tag, data, position, limit, registers);
|
||||
}
|
||||
|
||||
if (rawBytes != null) {
|
||||
unknownFields.storeField(
|
||||
WireFormat.makeTag(typeId, WireFormat.WIRETYPE_LENGTH_DELIMITED), rawBytes);
|
||||
}
|
||||
}
|
||||
if (position != limit) {
|
||||
throw InvalidProtocolBufferException.parseFailure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for wildcard capture of {@code unknownFieldSchema}. See:
|
||||
* https://docs.oracle.com/javase/tutorial/java/generics/capture.html
|
||||
*/
|
||||
private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> void mergeFromHelper(
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema,
|
||||
ExtensionSchema<ET> extensionSchema,
|
||||
T message,
|
||||
Reader reader,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
UB unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
|
||||
FieldSet<ET> extensions = extensionSchema.getMutableExtensions(message);
|
||||
try {
|
||||
while (true) {
|
||||
final int number = reader.getFieldNumber();
|
||||
if (number == Reader.READ_DONE) {
|
||||
return;
|
||||
}
|
||||
if (parseMessageSetItemOrUnknownField(
|
||||
reader,
|
||||
extensionRegistry,
|
||||
extensionSchema,
|
||||
extensions,
|
||||
unknownFieldSchema,
|
||||
unknownFields)) {
|
||||
continue;
|
||||
}
|
||||
// Done reading.
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
unknownFieldSchema.setBuilderToMessage(message, unknownFields);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeImmutable(T message) {
|
||||
unknownFieldSchema.makeImmutable(message);
|
||||
extensionSchema.makeImmutable(message);
|
||||
}
|
||||
|
||||
private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>>
|
||||
boolean parseMessageSetItemOrUnknownField(
|
||||
Reader reader,
|
||||
ExtensionRegistryLite extensionRegistry,
|
||||
ExtensionSchema<ET> extensionSchema,
|
||||
FieldSet<ET> extensions,
|
||||
UnknownFieldSchema<UT, UB> unknownFieldSchema,
|
||||
UB unknownFields)
|
||||
throws IOException {
|
||||
int startTag = reader.getTag();
|
||||
if (startTag != WireFormat.MESSAGE_SET_ITEM_TAG) {
|
||||
if (WireFormat.getTagWireType(startTag) == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
|
||||
Object extension =
|
||||
extensionSchema.findExtensionByNumber(
|
||||
extensionRegistry, defaultInstance, WireFormat.getTagFieldNumber(startTag));
|
||||
if (extension != null) {
|
||||
extensionSchema.parseLengthPrefixedMessageSetItem(
|
||||
reader, extension, extensionRegistry, extensions);
|
||||
return true;
|
||||
} else {
|
||||
return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader);
|
||||
}
|
||||
} else {
|
||||
return reader.skipField();
|
||||
}
|
||||
}
|
||||
|
||||
// The wire format for MessageSet is:
|
||||
// message MessageSet {
|
||||
// repeated group Item = 1 {
|
||||
// required uint32 typeId = 2;
|
||||
// required bytes message = 3;
|
||||
// }
|
||||
// }
|
||||
// "typeId" is the extension's field number. The extension can only be
|
||||
// a message type, where "message" contains the encoded bytes of that
|
||||
// message.
|
||||
//
|
||||
// In practice, we will probably never see a MessageSet item in which
|
||||
// the message appears before the type ID, or where either field does not
|
||||
// appear exactly once. However, in theory such cases are valid, so we
|
||||
// should be prepared to accept them.
|
||||
|
||||
int typeId = 0;
|
||||
ByteString rawBytes = null; // If we encounter "message" before "typeId"
|
||||
Object extension = null;
|
||||
|
||||
// Read bytes from input, if we get it's type first then parse it eagerly,
|
||||
// otherwise we store the raw bytes in a local variable.
|
||||
loop:
|
||||
while (true) {
|
||||
final int number = reader.getFieldNumber();
|
||||
if (number == Reader.READ_DONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
final int tag = reader.getTag();
|
||||
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
|
||||
typeId = reader.readUInt32();
|
||||
extension =
|
||||
extensionSchema.findExtensionByNumber(extensionRegistry, defaultInstance, typeId);
|
||||
continue;
|
||||
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
|
||||
if (extension != null) {
|
||||
extensionSchema.parseLengthPrefixedMessageSetItem(
|
||||
reader, extension, extensionRegistry, extensions);
|
||||
continue;
|
||||
}
|
||||
// We haven't seen a type ID yet or we want parse message lazily.
|
||||
rawBytes = reader.readBytes();
|
||||
continue;
|
||||
} else {
|
||||
if (!reader.skipField()) {
|
||||
break loop; // End of group
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.getTag() != WireFormat.MESSAGE_SET_ITEM_END_TAG) {
|
||||
throw InvalidProtocolBufferException.invalidEndTag();
|
||||
}
|
||||
|
||||
// If there are any rawBytes left, it means the message content appears before the type ID.
|
||||
if (rawBytes != null) {
|
||||
if (extension != null) { // We known the type
|
||||
// TODO(xiaofeng): Instead of reading into a temporary ByteString, maybe there is a way
|
||||
// to read directly from Reader to the submessage?
|
||||
extensionSchema.parseMessageSetItem(rawBytes, extension, extensionRegistry, extensions);
|
||||
} else {
|
||||
unknownFieldSchema.addLengthDelimited(unknownFields, typeId, rawBytes);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isInitialized(T message) {
|
||||
FieldSet<?> extensions = extensionSchema.getExtensions(message);
|
||||
return extensions.isInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize(T message) {
|
||||
int size = 0;
|
||||
|
||||
size += getUnknownFieldsSerializedSize(unknownFieldSchema, message);
|
||||
|
||||
if (hasExtensions) {
|
||||
size += extensionSchema.getExtensions(message).getMessageSetSerializedSize();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private <UT, UB> int getUnknownFieldsSerializedSize(
|
||||
UnknownFieldSchema<UT, UB> schema, T message) {
|
||||
UT unknowns = schema.getFromMessage(message);
|
||||
return schema.getSerializedSizeAsMessageSet(unknowns);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** Verifies that an object is mutable, throwing if not. */
|
||||
interface MutabilityOracle {
|
||||
static final MutabilityOracle IMMUTABLE =
|
||||
new MutabilityOracle() {
|
||||
@Override
|
||||
public void ensureMutable() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
/** Throws an {@link UnsupportedOperationException} if not mutable. */
|
||||
void ensureMutable();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
@CheckReturnValue
|
||||
interface NewInstanceSchema {
|
||||
/** Create a new message instance given the default instance of the message type. */
|
||||
Object newInstance(Object defaultInstance);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
final class NewInstanceSchemaFull implements NewInstanceSchema {
|
||||
@Override
|
||||
public Object newInstance(Object defaultInstance) {
|
||||
return ((GeneratedMessageV3) defaultInstance)
|
||||
.newInstance(GeneratedMessageV3.UnusedPrivateParameter.INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
@CheckReturnValue
|
||||
final class NewInstanceSchemaLite implements NewInstanceSchema {
|
||||
@Override
|
||||
public Object newInstance(Object defaultInstance) {
|
||||
// TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
|
||||
// better.
|
||||
return ((GeneratedMessageLite<?, ?>) defaultInstance).newMutableInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
@CheckReturnValue
|
||||
final class NewInstanceSchemas {
|
||||
private static final NewInstanceSchema FULL_SCHEMA = loadSchemaForFullRuntime();
|
||||
private static final NewInstanceSchema LITE_SCHEMA = new NewInstanceSchemaLite();
|
||||
|
||||
static NewInstanceSchema full() {
|
||||
return FULL_SCHEMA;
|
||||
}
|
||||
|
||||
static NewInstanceSchema lite() {
|
||||
return LITE_SCHEMA;
|
||||
}
|
||||
|
||||
private static NewInstanceSchema loadSchemaForFullRuntime() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.google.protobuf.NewInstanceSchemaFull");
|
||||
return (NewInstanceSchema) clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.InvalidMarkException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** A {@link ByteString} that wraps around a {@link ByteBuffer}. */
|
||||
final class NioByteString extends ByteString.LeafByteString {
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
NioByteString(ByteBuffer buffer) {
|
||||
checkNotNull(buffer, "buffer");
|
||||
|
||||
// Use native byte order for fast fixed32/64 operations.
|
||||
this.buffer = buffer.slice().order(ByteOrder.nativeOrder());
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Serializable
|
||||
|
||||
/** Magic method that lets us override serialization behavior. */
|
||||
private Object writeReplace() {
|
||||
return ByteString.copyFrom(buffer.slice());
|
||||
}
|
||||
|
||||
/** 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");
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
@Override
|
||||
public byte byteAt(int index) {
|
||||
try {
|
||||
return buffer.get(index);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw e;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new ArrayIndexOutOfBoundsException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte internalByteAt(int index) {
|
||||
// it isn't possible to avoid the bounds checking inside of ByteBuffer, so just use the default
|
||||
// implementation.
|
||||
return byteAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return buffer.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString substring(int beginIndex, int endIndex) {
|
||||
try {
|
||||
ByteBuffer slice = slice(beginIndex, endIndex);
|
||||
return new NioByteString(slice);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw e;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new ArrayIndexOutOfBoundsException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void copyToInternal(
|
||||
byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
|
||||
ByteBuffer slice = buffer.slice();
|
||||
((Buffer) slice).position(sourceOffset);
|
||||
slice.get(target, targetOffset, numberToCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(ByteBuffer target) {
|
||||
target.put(buffer.slice());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream out) throws IOException {
|
||||
out.write(toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean equalsRange(ByteString other, int offset, int length) {
|
||||
return substring(0, length).equals(other.substring(offset, offset + length));
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) throws IOException {
|
||||
if (buffer.hasArray()) {
|
||||
// Optimized write for array-backed buffers.
|
||||
// Note that we're taking the risk that a malicious OutputStream could modify the array.
|
||||
int bufferOffset = buffer.arrayOffset() + buffer.position() + sourceOffset;
|
||||
out.write(buffer.array(), bufferOffset, numberToWrite);
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBufferWriter.write(slice(sourceOffset, sourceOffset + numberToWrite), out);
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeTo(ByteOutput output) throws IOException {
|
||||
output.writeLazy(buffer.slice());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer asReadOnlyByteBuffer() {
|
||||
return buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ByteBuffer> asReadOnlyByteBufferList() {
|
||||
return Collections.singletonList(asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringInternal(Charset charset) {
|
||||
final byte[] bytes;
|
||||
final int offset;
|
||||
final int length;
|
||||
if (buffer.hasArray()) {
|
||||
bytes = buffer.array();
|
||||
offset = buffer.arrayOffset() + buffer.position();
|
||||
length = buffer.remaining();
|
||||
} else {
|
||||
// TODO(nathanmittler): Can we optimize this?
|
||||
bytes = toByteArray();
|
||||
offset = 0;
|
||||
length = bytes.length;
|
||||
}
|
||||
return new String(bytes, offset, length, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidUtf8() {
|
||||
return Utf8.isValidUtf8(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int partialIsValidUtf8(int state, int offset, int length) {
|
||||
return Utf8.partialIsValidUtf8(state, buffer, offset, offset + length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ByteString)) {
|
||||
return false;
|
||||
}
|
||||
ByteString otherString = ((ByteString) other);
|
||||
if (size() != otherString.size()) {
|
||||
return false;
|
||||
}
|
||||
if (size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if (other instanceof NioByteString) {
|
||||
return buffer.equals(((NioByteString) other).buffer);
|
||||
}
|
||||
if (other instanceof RopeByteString) {
|
||||
return other.equals(this);
|
||||
}
|
||||
return buffer.equals(otherString.asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int partialHash(int h, int offset, int length) {
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
h = h * 31 + buffer.get(i);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInput() {
|
||||
return new InputStream() {
|
||||
private final ByteBuffer buf = buffer.slice();
|
||||
|
||||
@Override
|
||||
public void mark(int readlimit) {
|
||||
buf.mark();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
try {
|
||||
buf.reset();
|
||||
} catch (InvalidMarkException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return buf.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
return buf.get() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] bytes, int off, int len) throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = Math.min(len, buf.remaining());
|
||||
buf.get(bytes, off, len);
|
||||
return len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodedInputStream newCodedInput() {
|
||||
return CodedInputStream.newInstance(buffer, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a slice of a range of this buffer.
|
||||
*
|
||||
* @param beginIndex the beginning index of the slice (inclusive).
|
||||
* @param endIndex the end index of the slice (exclusive).
|
||||
* @return the requested slice.
|
||||
*/
|
||||
private ByteBuffer slice(int beginIndex, int endIndex) {
|
||||
if (beginIndex < buffer.position() || endIndex > buffer.limit() || beginIndex > endIndex) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid indices [%d, %d]", beginIndex, endIndex));
|
||||
}
|
||||
|
||||
ByteBuffer slice = buffer.slice();
|
||||
((Buffer) slice).position(beginIndex - buffer.position());
|
||||
((Buffer) slice).limit(endIndex - buffer.position());
|
||||
return slice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/** Information for a oneof within a protobuf message. */
|
||||
// TODO(nathanmittler): make this private once all of experimental code is migrated to protobuf.
|
||||
@ExperimentalApi
|
||||
@CheckReturnValue
|
||||
final class OneofInfo {
|
||||
private final int id;
|
||||
private final Field caseField;
|
||||
private final Field valueField;
|
||||
|
||||
public OneofInfo(int id, Field caseField, Field valueField) {
|
||||
this.id = id;
|
||||
this.caseField = caseField;
|
||||
this.valueField = valueField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of the oneof within the message. This is really just an index
|
||||
* starting at zero.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** The {@code int} field containing the field number of the currently active member. */
|
||||
public Field getCaseField() {
|
||||
return caseField;
|
||||
}
|
||||
|
||||
/** The {@link Object} field containing the value of the currently active member. */
|
||||
public Field getValueField() {
|
||||
return valueField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Abstract interface for parsing Protocol Messages.
|
||||
*
|
||||
* <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
|
||||
* I/O problem occurs, an exception is thrown with an {@link java.io.IOException} cause.
|
||||
*
|
||||
* @author liujisi@google.com (Pherl Liu)
|
||||
*/
|
||||
public interface Parser<MessageType> {
|
||||
|
||||
// NB(jh): Other parts of the protobuf API that parse messages distinguish between an I/O problem
|
||||
// (like failure reading bytes from a socket) and invalid data (encoding error) via the type of
|
||||
// thrown exception. But it would be source-incompatible to make the methods in this interface do
|
||||
// so since they were originally spec'ed to only throw InvalidProtocolBufferException. So callers
|
||||
// must inspect the cause of the exception to distinguish these two cases.
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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 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)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
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)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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)}.
|
||||
*/
|
||||
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
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
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)}.
|
||||
*/
|
||||
public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Like {@link #parseFrom(InputStream)}, but does not read until 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.
|
||||
*/
|
||||
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 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.
|
||||
*/
|
||||
public MessageType parsePartialDelimitedFrom(
|
||||
InputStream input, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** A marker interface indicating that the collection supports primitives and is non-boxing. */
|
||||
interface PrimitiveNonBoxingCollection {}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** Represents the syntax version of the message. */
|
||||
@ExperimentalApi
|
||||
public enum ProtoSyntax {
|
||||
PROTO2,
|
||||
PROTO3;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Main runtime interface for protobuf. Applications should interact with this interface (rather
|
||||
* than directly accessing internal APIs) in order to perform operations on protobuf messages.
|
||||
*/
|
||||
@ExperimentalApi
|
||||
@CheckReturnValue
|
||||
final class Protobuf {
|
||||
private static final Protobuf INSTANCE = new Protobuf();
|
||||
|
||||
private final SchemaFactory schemaFactory;
|
||||
|
||||
// TODO(nathanmittler): Consider using ClassValue instead.
|
||||
private final ConcurrentMap<Class<?>, Schema<?>> schemaCache =
|
||||
new ConcurrentHashMap<Class<?>, Schema<?>>();
|
||||
|
||||
/** Gets the singleton instance of the Protobuf runtime. */
|
||||
public static Protobuf getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/** Writes the given message to the target {@link Writer}. */
|
||||
public <T> void writeTo(T message, Writer writer) throws IOException {
|
||||
schemaFor(message).writeTo(message, writer);
|
||||
}
|
||||
|
||||
/** Reads fields from the given {@link Reader} and merges them into the message. */
|
||||
public <T> void mergeFrom(T message, Reader reader) throws IOException {
|
||||
mergeFrom(message, reader, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
/** Reads fields from the given {@link Reader} and merges them into the message. */
|
||||
public <T> void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
schemaFor(message).mergeFrom(message, reader, extensionRegistry);
|
||||
}
|
||||
|
||||
/** Marks repeated/map/extension/unknown fields as immutable. */
|
||||
public <T> void makeImmutable(T message) {
|
||||
schemaFor(message).makeImmutable(message);
|
||||
}
|
||||
|
||||
/** Checks if all required fields are set. */
|
||||
<T> boolean isInitialized(T message) {
|
||||
return schemaFor(message).isInitialized(message);
|
||||
}
|
||||
|
||||
/** Gets the schema for the given message type. */
|
||||
public <T> Schema<T> schemaFor(Class<T> messageType) {
|
||||
checkNotNull(messageType, "messageType");
|
||||
@SuppressWarnings("unchecked")
|
||||
Schema<T> schema = (Schema<T>) schemaCache.get(messageType);
|
||||
if (schema == null) {
|
||||
schema = schemaFactory.createSchema(messageType);
|
||||
@SuppressWarnings("unchecked")
|
||||
Schema<T> previous = (Schema<T>) registerSchema(messageType, schema);
|
||||
if (previous != null) {
|
||||
// A new schema was registered by another thread.
|
||||
schema = previous;
|
||||
}
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
/** Gets the schema for the given message. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Schema<T> schemaFor(T message) {
|
||||
return schemaFor((Class<T>) message.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given schema for the message type only if a schema was not already registered.
|
||||
*
|
||||
* @param messageType the type of message on which the schema operates.
|
||||
* @param schema the schema for the message type.
|
||||
* @return the previously registered schema, or {@code null} if the given schema was successfully
|
||||
* registered.
|
||||
*/
|
||||
public Schema<?> registerSchema(Class<?> messageType, Schema<?> schema) {
|
||||
checkNotNull(messageType, "messageType");
|
||||
checkNotNull(schema, "schema");
|
||||
return schemaCache.putIfAbsent(messageType, schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visible for testing only. Registers the given schema for the message type. If a schema was
|
||||
* previously registered, it will be replaced by the provided schema.
|
||||
*
|
||||
* @param messageType the type of message on which the schema operates.
|
||||
* @param schema the schema for the message type.
|
||||
* @return the previously registered schema, or {@code null} if no schema was registered
|
||||
* previously.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Schema<?> registerSchemaOverride(Class<?> messageType, Schema<?> schema) {
|
||||
checkNotNull(messageType, "messageType");
|
||||
checkNotNull(schema, "schema");
|
||||
return schemaCache.put(messageType, schema);
|
||||
}
|
||||
|
||||
private Protobuf() {
|
||||
schemaFactory = new ManifestSchemaFactory();
|
||||
}
|
||||
|
||||
int getTotalSchemaSize() {
|
||||
int result = 0;
|
||||
for (Schema<?> schema : schemaCache.values()) {
|
||||
if (schema instanceof MessageSchema) {
|
||||
result += ((MessageSchema) schema).getSchemaSize();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
import java.util.Arrays;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/** Implements {@link ProtobufList} for non-primitive and {@link String} types. */
|
||||
final class ProtobufArrayList<E> extends AbstractProtobufList<E> implements RandomAccess {
|
||||
|
||||
private static final ProtobufArrayList<Object> EMPTY_LIST =
|
||||
new ProtobufArrayList<Object>(new Object[0], 0);
|
||||
|
||||
static {
|
||||
EMPTY_LIST.makeImmutable();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Guaranteed safe by runtime.
|
||||
public static <E> ProtobufArrayList<E> emptyList() {
|
||||
return (ProtobufArrayList<E>) EMPTY_LIST;
|
||||
}
|
||||
|
||||
private E[] array;
|
||||
private int size;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ProtobufArrayList() {
|
||||
this((E[]) new Object[DEFAULT_CAPACITY], 0);
|
||||
}
|
||||
|
||||
private ProtobufArrayList(E[] array, int size) {
|
||||
this.array = array;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
|
||||
if (capacity < size) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
E[] newArray = Arrays.copyOf(array, capacity);
|
||||
|
||||
return new ProtobufArrayList<E>(newArray, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (size == array.length) {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
E[] newArray = Arrays.copyOf(array, length);
|
||||
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[size++] = element;
|
||||
modCount++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (index < 0 || index > size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
|
||||
if (size < array.length) {
|
||||
// Shift everything over to make room
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
} else {
|
||||
// Resize to 1.5x the size
|
||||
int length = ((size * 3) / 2) + 1;
|
||||
E[] newArray = createArray(length);
|
||||
|
||||
// Copy the first part directly
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
|
||||
// Copy the rest shifted over by one to make room
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[index] = element;
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
ensureIndexInRange(index);
|
||||
return array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
|
||||
E value = array[index];
|
||||
if (index < size - 1) {
|
||||
System.arraycopy(array, index + 1, array, index, size - index - 1);
|
||||
}
|
||||
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
ensureIsMutable();
|
||||
ensureIndexInRange(index);
|
||||
|
||||
E toReturn = array[index];
|
||||
array[index] = element;
|
||||
|
||||
modCount++;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E> E[] createArray(int capacity) {
|
||||
return (E[]) new Object[capacity];
|
||||
}
|
||||
|
||||
private void ensureIndexInRange(int index) {
|
||||
if (index < 0 || index >= size) {
|
||||
throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeOutOfBoundsExceptionMessage(int index) {
|
||||
return "Index:" + index + ", Size:" + size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.BooleanList;
|
||||
import com.google.protobuf.Internal.DoubleList;
|
||||
import com.google.protobuf.Internal.FloatList;
|
||||
import com.google.protobuf.Internal.IntList;
|
||||
import com.google.protobuf.Internal.LongList;
|
||||
import com.google.protobuf.Internal.ProtobufList;
|
||||
|
||||
/** Utility class for construction of lists that extend {@link ProtobufList}. */
|
||||
@ExperimentalApi
|
||||
@CheckReturnValue
|
||||
final class ProtobufLists {
|
||||
private ProtobufLists() {}
|
||||
|
||||
public static <E> ProtobufList<E> emptyProtobufList() {
|
||||
return ProtobufArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) {
|
||||
int size = list.size();
|
||||
return list.mutableCopyWithCapacity(
|
||||
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
|
||||
}
|
||||
|
||||
public static BooleanList emptyBooleanList() {
|
||||
return BooleanArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static BooleanList newBooleanList() {
|
||||
return new BooleanArrayList();
|
||||
}
|
||||
|
||||
public static IntList emptyIntList() {
|
||||
return IntArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static IntList newIntList() {
|
||||
return new IntArrayList();
|
||||
}
|
||||
|
||||
public static LongList emptyLongList() {
|
||||
return LongArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static LongList newLongList() {
|
||||
return new LongArrayList();
|
||||
}
|
||||
|
||||
public static FloatList emptyFloatList() {
|
||||
return FloatArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static FloatList newFloatList() {
|
||||
return new FloatArrayList();
|
||||
}
|
||||
|
||||
public static DoubleList emptyDoubleList() {
|
||||
return DoubleArrayList.emptyList();
|
||||
}
|
||||
|
||||
public static DoubleList newDoubleList() {
|
||||
return new DoubleArrayList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
|
||||
/** 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. */
|
||||
@Override
|
||||
int getNumber();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
EnumDescriptor getDescriptorForType();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.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.
|
||||
*/
|
||||
public interface ProtocolStringList extends List<String> {
|
||||
|
||||
/** Returns a view of the data as a list of ByteStrings. */
|
||||
List<ByteString> asByteStringList();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user