Merge commit '36bca61764984ff5395653cf8377ec5daa71b709' as 'libs/protobuf'

This commit is contained in:
Henry Winkel
2022-10-22 14:46:58 +02:00
2186 changed files with 838730 additions and 0 deletions
+493
View 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__"],
)
@@ -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>
@@ -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
View 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
View 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
@@ -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);
}
}
}
@@ -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();
}
@@ -0,0 +1,222 @@
// 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;
/**
* RawMessageInfo stores the same amount of information as {@link MessageInfo} but in a more compact
* format.
*/
@CheckReturnValue
final class RawMessageInfo implements MessageInfo {
private final MessageLite defaultInstance;
/**
* The compact format packs everything in a String object and a Object[] array. The String object
* is encoded with field number, field type, hasbits offset, oneof index, etc., whereas the
* Object[] array contains field references, class references, instance references, etc.
*
* <p>The String object encodes a sequence of integers into UTF-16 characters. For each int, it
* will be encoding into 1 to 3 UTF-16 characters depending on its unsigned value:
*
* <ul>
* <li>1 char: [c1: 0x0000 - 0xD7FF] = int of the same value.
* <li>2 chars: [c1: 0xE000 - 0xFFFF], [c2: 0x0000 - 0xD7FF] = (c2 << 13) | (c1 & 0x1FFF)
* <li>3 chars: [c1: 0xE000 - 0xFFFF], [c2: 0xE000 - 0xFFFF], [c3: 0x0000 - 0xD7FF] = (c3 << 26)
* | ((c2 & 0x1FFF) << 13) | (c1 & 0x1FFF)
* </ul>
*
* <p>Note that we don't use UTF-16 surrogate pairs [0xD800 - 0xDFFF] because they have to come in
* pairs to form a valid UTF-16char sequence and don't help us encode values more efficiently.
*
* <p>The integer sequence encoded in the String object has the following layout:
*
* <ul>
* <li>[0]: flags, flags & 0x1 = is proto2?, flags & 0x2 = is message?.
* <li>[1]: field count, if 0, this is the end of the integer sequence and the corresponding
* Object[] array should be null.
* <li>[2]: oneof count
* <li>[3]: hasbits count, how many hasbits integers are generated.
* <li>[4]: min field number
* <li>[5]: max field number
* <li>[6]: total number of entries need to allocate
* <li>[7]: map field count
* <li>[8]: repeated field count, this doesn't include map fields.
* <li>[9]: size of checkInitialized array
* <li>[...]: field entries
* </ul>
*
* <p>Each field entry starts with a field number and the field type:
*
* <ul>
* <li>[0]: field number
* <li>[1]: field type with extra bits:
* <ul>
* <li>v & 0xFF = field type as defined in the FieldType class
* <li>v & 0x0100 = is required?
* <li>v & 0x0200 = is checkUtf8?
* <li>v & 0x0400 = needs isInitialized check?
* <li>v & 0x0800 = is map field with proto2 enum value?
* <li>v & 0x1000 = supports presence checking?
* </ul>
* </ul>
*
* If the (singular) field supports presence checking:
*
* <ul>
* <li>[2]: hasbits offset
* </ul>
*
* If the field is in an oneof:
*
* <ul>
* <li>[2]: oneof index
* </ul>
*
* For other types, the field entry only has field number and field type.
*
* <p>The Object[] array has 3 sections:
*
* <ul>
* <li>---- oneof section ----
* <ul>
* <li>[0]: value field for oneof 1.
* <li>[1]: case field for oneof 1.
* <li>...
* <li>[.]: value field for oneof n.
* <li>[.]: case field for oneof n.
* </ul>
* <li>---- hasbits section ----
* <ul>
* <li>[.]: hasbits field 1
* <li>[.]: hasbits field 2
* <li>...
* <li>[.]: hasbits field n
* </ul>
* <li>---- field section ----
* <ul>
* <li>[...]: field entries
* </ul>
* </ul>
*
* <p>In the Object[] array, field entries are ordered in the same way as field entries in the
* String object. The size of each entry is determined by the field type.
*
* <ul>
* <li>Oneof field:
* <ul>
* <li>Oneof message field:
* <ul>
* <li>[0]: message class reference.
* </ul>
* <li>Oneof enum fieldin proto2:
* <ul>
* <li>[0]: EnumLiteMap
* </ul>
* <li>For all other oneof fields, field entry in the Object[] array is empty.
* </ul>
* <li>Repeated message field:
* <ul>
* <li>[0]: field reference
* <li>[1]: message class reference
* </ul>
* <li>Proto2 singular/repeated enum field:
* <ul>
* <li>[0]: field reference
* <li>[1]: EnumLiteMap
* </ul>
* <li>Map field with a proto2 enum value:
* <ul>
* <li>[0]: field reference
* <li>[1]: map default entry instance
* <li>[2]: EnumLiteMap
* </ul>
* <li>Map field with other value types:
* <ul>
* <li>[0]: field reference
* <li>[1]: map default entry instance
* </ul>
* <li>All other field type:
* <ul>
* <li>[0]: field reference
* </ul>
* </ul>
*
* <p>In order to read the field info from this compact format, a reader needs to progress through
* the String object and the Object[] array simultaneously.
*/
private final String info;
private final Object[] objects;
private final int flags;
RawMessageInfo(MessageLite defaultInstance, String info, Object[] objects) {
this.defaultInstance = defaultInstance;
this.info = info;
this.objects = objects;
int position = 0;
int value = (int) info.charAt(position++);
if (value < 0xD800) {
flags = value;
} else {
int result = value & 0x1FFF;
int shift = 13;
while ((value = info.charAt(position++)) >= 0xD800) {
result |= (value & 0x1FFF) << shift;
shift += 13;
}
flags = result | (value << shift);
}
}
String getStringInfo() {
return info;
}
Object[] getObjects() {
return objects;
}
@Override
public MessageLite getDefaultInstance() {
return defaultInstance;
}
@Override
public ProtoSyntax getSyntax() {
return (flags & 0x1) == 0x1 ? ProtoSyntax.PROTO2 : ProtoSyntax.PROTO3;
}
@Override
public boolean isMessageSetWireFormat() {
return (flags & 0x2) == 0x2;
}
}
@@ -0,0 +1,388 @@
// 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.List;
import java.util.Map;
/** A reader of fields from a serialized protobuf message. */
// TODO(nathanmittler): Refactor to allow the reader to allocate properly sized lists.
@ExperimentalApi
@CheckReturnValue
interface Reader {
/** Value used to indicate that the end of input has been reached. */
int READ_DONE = Integer.MAX_VALUE;
/** Value used to indicate that the reader does not know the tag about the field. */
int TAG_UNKNOWN = 0;
boolean shouldDiscardUnknownFields();
/**
* Gets the field number for the current field being read.
*
* <p>TODO(liujisi): Rename it to make it more explicit about the side effect on the underlying
* buffer.
*
* @return the current field number or {@link #READ_DONE} if the end of input has been reached.
*/
int getFieldNumber() throws IOException;
/**
* Gets the wire tag of the current field.
*
* @return the current wire tag or {@link #TAG_UNKNOWN} if the reader does not know the tag of the
* current field.
*/
int getTag();
/**
* Skips the current field and advances the reader to the next field.
*
* @return {@code true} if there are more fields or {@code false} if the end of input has been
* reached.
*/
boolean skipField() throws IOException;
/**
* Reads and returns the next field of type {@code DOUBLE} and advances the reader to the next
* field.
*/
double readDouble() throws IOException;
/**
* Reads and returns the next field of type {@code FLOAT} and advances the reader to the next
* field.
*/
float readFloat() throws IOException;
/**
* Reads and returns the next field of type {@code UINT64} and advances the reader to the next
* field.
*/
long readUInt64() throws IOException;
/**
* Reads and returns the next field of type {@code INT64} and advances the reader to the next
* field.
*/
long readInt64() throws IOException;
/**
* Reads and returns the next field of type {@code INT32} and advances the reader to the next
* field.
*/
int readInt32() throws IOException;
/**
* Reads and returns the next field of type {@code FIXED64} and advances the reader to the next
* field.
*/
long readFixed64() throws IOException;
/**
* Reads and returns the next field of type {@code FIXED32} and advances the reader to the next
* field.
*/
int readFixed32() throws IOException;
/**
* Reads and returns the next field of type {@code BOOL} and advances the reader to the next
* field.
*/
boolean readBool() throws IOException;
/**
* Reads and returns the next field of type {@code STRING} and advances the reader to the next
* field. If the stream contains malformed UTF-8, replace the offending bytes with the standard
* UTF-8 replacement character.
*/
String readString() throws IOException;
/**
* Reads and returns the next field of type {@code STRING} and advances the reader to the next
* field. If the stream contains malformed UTF-8, throw exception {@link
* InvalidProtocolBufferException}.
*/
String readStringRequireUtf8() throws IOException;
// TODO(yilunchong): the lack of other opinions for whether to expose this on the interface
<T> T readMessageBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Reads and returns the next field of type {@code MESSAGE} and advances the reader to the next
* field.
*/
<T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry) throws IOException;
/**
* Reads and returns the next field of type {@code GROUP} and advances the reader to the next
* field.
*
* @deprecated groups fields are deprecated.
*/
@Deprecated
<T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry) throws IOException;
// TODO(yilunchong): the lack of other opinions for whether to expose this on the interface
@Deprecated
<T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException;
/** Read a message field from the wire format and merge the results into the given target. */
<T> void mergeMessageField(T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException;
/** Read a group field from the wire format and merge the results into the given target. */
<T> void mergeGroupField(T target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Reads and returns the next field of type {@code BYTES} and advances the reader to the next
* field.
*/
ByteString readBytes() throws IOException;
/**
* Reads and returns the next field of type {@code UINT32} and advances the reader to the next
* field.
*/
int readUInt32() throws IOException;
/**
* Reads and returns the next field of type {@code ENUM} and advances the reader to the next
* field.
*/
int readEnum() throws IOException;
/**
* Reads and returns the next field of type {@code SFIXED32} and advances the reader to the next
* field.
*/
int readSFixed32() throws IOException;
/**
* Reads and returns the next field of type {@code SFIXED64} and advances the reader to the next
* field.
*/
long readSFixed64() throws IOException;
/**
* Reads and returns the next field of type {@code SINT32} and advances the reader to the next
* field.
*/
int readSInt32() throws IOException;
/**
* Reads and returns the next field of type {@code SINT64} and advances the reader to the next
* field.
*/
long readSInt64() throws IOException;
/**
* Reads the next field of type {@code DOUBLE_LIST} or {@code DOUBLE_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readDoubleList(List<Double> target) throws IOException;
/**
* Reads the next field of type {@code FLOAT_LIST} or {@code FLOAT_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readFloatList(List<Float> target) throws IOException;
/**
* Reads the next field of type {@code UINT64_LIST} or {@code UINT64_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readUInt64List(List<Long> target) throws IOException;
/**
* Reads the next field of type {@code INT64_LIST} or {@code INT64_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readInt64List(List<Long> target) throws IOException;
/**
* Reads the next field of type {@code INT32_LIST} or {@code INT32_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readInt32List(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code FIXED64_LIST} or {@code FIXED64_LIST_PACKED} and advances
* the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readFixed64List(List<Long> target) throws IOException;
/**
* Reads the next field of type {@code FIXED32_LIST} or {@code FIXED32_LIST_PACKED} and advances
* the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readFixed32List(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code BOOL_LIST} or {@code BOOL_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readBoolList(List<Boolean> target) throws IOException;
/**
* Reads the next field of type {@code STRING_LIST} and advances the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readStringList(List<String> target) throws IOException;
/**
* Reads the next field of type {@code STRING_LIST} and advances the reader to the next field. If
* the stream contains malformed UTF-8, throw exception {@link InvalidProtocolBufferException}.
*
* @param target the list that will receive the read values.
*/
void readStringListRequireUtf8(List<String> target) throws IOException;
/**
* Reads the next field of type {@code MESSAGE_LIST} and advances the reader to the next field.
*
* @param target the list that will receive the read values.
* @param targetType the type of the elements stored in the {@code target} list.
*/
<T> void readMessageList(
List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException;
<T> void readMessageList(
List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Reads the next field of type {@code GROUP_LIST} and advances the reader to the next field.
*
* @param target the list that will receive the read values.
* @param targetType the type of the elements stored in the {@code target} list.
* @deprecated groups fields are deprecated.
*/
@Deprecated
<T> void readGroupList(
List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry)
throws IOException;
@Deprecated
<T> void readGroupList(
List<T> target, Schema<T> targetType, ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Reads the next field of type {@code BYTES_LIST} and advances the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readBytesList(List<ByteString> target) throws IOException;
/**
* Reads the next field of type {@code UINT32_LIST} or {@code UINT32_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readUInt32List(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code ENUM_LIST} or {@code ENUM_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readEnumList(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code SFIXED32_LIST} or {@code SFIXED32_LIST_PACKED} and advances
* the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readSFixed32List(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code SFIXED64_LIST} or {@code SFIXED64_LIST_PACKED} and advances
* the reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readSFixed64List(List<Long> target) throws IOException;
/**
* Reads the next field of type {@code SINT32_LIST} or {@code SINT32_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readSInt32List(List<Integer> target) throws IOException;
/**
* Reads the next field of type {@code SINT64_LIST} or {@code SINT64_LIST_PACKED} and advances the
* reader to the next field.
*
* @param target the list that will receive the read values.
*/
void readSInt64List(List<Long> target) throws IOException;
/**
* Reads the next field of type {@code MAP} and advances the reader to the next field.
*
* @param target the mutable map that will receive the read values.
* @param mapDefaultEntry the default entry of the map field.
* @param extensionRegistry the extension registry for parsing message value fields.
*/
<K, V> void readMap(
Map<K, V> target,
MapEntryLite.Metadata<K, V> mapDefaultEntry,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
@@ -0,0 +1,670 @@
// 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.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
/**
* {@code RepeatedFieldBuilder} implements a structure that a protocol message uses to hold a
* repeated field of other protocol messages. It supports the classical use case of adding immutable
* {@link Message}'s to the repeated field and is highly optimized around this (no extra memory
* allocations and sharing of immutable arrays). <br>
* It also supports the additional use case of adding a {@link Message.Builder} to the repeated
* field and deferring conversion of that {@code Builder} to an immutable {@code Message}. In this
* way, it's possible to maintain a tree of {@code Builder}'s that acts as a fully read/write data
* structure. <br>
* Logically, one can think of a tree of builders as converting the entire tree to messages when
* build is called on the root or when any method is called that desires a Message instead of a
* Builder. In terms of the implementation, the {@code SingleFieldBuilder} and {@code
* RepeatedFieldBuilder} classes cache messages that were created so that messages only need to be
* created when some change occurred in its builder or a builder for one of its descendants.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
* @author jonp@google.com (Jon Perlow)
*/
public class RepeatedFieldBuilder<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
implements GeneratedMessage.BuilderParent {
// Parent to send changes to.
private GeneratedMessage.BuilderParent parent;
// List of messages. Never null. It may be immutable, in which case
// isMessagesListMutable will be false. See note below.
private List<MType> messages;
// Whether messages is an mutable array that can be modified.
private boolean isMessagesListMutable;
// List of builders. May be null, in which case, no nested builders were
// created. If not null, entries represent the builder for that index.
private List<SingleFieldBuilder<MType, BType, IType>> builders;
// Here are the invariants for messages and builders:
// 1. messages is never null and its count corresponds to the number of items
// in the repeated field.
// 2. If builders is non-null, messages and builders MUST always
// contain the same number of items.
// 3. Entries in either array can be null, but for any index, there MUST be
// either a Message in messages or a builder in builders.
// 4. If the builder at an index is non-null, the builder is
// authoritative. This is the case where a Builder was set on the index.
// Any message in the messages array MUST be ignored.
// t. If the builder at an index is null, the message in the messages
// list is authoritative. This is the case where a Message (not a Builder)
// was set directly for an index.
// Indicates that we've built a message and so we are now obligated
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
private boolean isClean;
// A view of this builder that exposes a List interface of messages. This is
// initialized on demand. This is fully backed by this object and all changes
// are reflected in it. Access to any item converts it to a message if it
// was a builder.
private MessageExternalList<MType, BType, IType> externalMessageList;
// A view of this builder that exposes a List interface of builders. This is
// initialized on demand. This is fully backed by this object and all changes
// are reflected in it. Access to any item converts it to a builder if it
// was a message.
private BuilderExternalList<MType, BType, IType> externalBuilderList;
// A view of this builder that exposes a List interface of the interface
// implemented by messages and builders. This is initialized on demand. This
// is fully backed by this object and all changes are reflected in it.
// Access to any item returns either a builder or message depending on
// what is most efficient.
private MessageOrBuilderExternalList<MType, BType, IType> externalMessageOrBuilderList;
/**
* Constructs a new builder with an empty list of messages.
*
* @param messages the current list of messages
* @param isMessagesListMutable Whether the messages list is mutable
* @param parent a listener to notify of changes
* @param isClean whether the builder is initially marked clean
*/
public RepeatedFieldBuilder(
List<MType> messages,
boolean isMessagesListMutable,
GeneratedMessage.BuilderParent parent,
boolean isClean) {
this.messages = messages;
this.isMessagesListMutable = isMessagesListMutable;
this.parent = parent;
this.isClean = isClean;
}
public void dispose() {
// Null out parent so we stop sending it invalidations.
parent = null;
}
/**
* Ensures that the list of messages is mutable so it can be updated. If it's immutable, a copy is
* made.
*/
private void ensureMutableMessageList() {
if (!isMessagesListMutable) {
messages = new ArrayList<MType>(messages);
isMessagesListMutable = true;
}
}
/**
* Ensures that the list of builders is not null. If it's null, the list is created and
* initialized to be the same size as the messages list with null entries.
*/
private void ensureBuilders() {
if (this.builders == null) {
this.builders = new ArrayList<SingleFieldBuilder<MType, BType, IType>>(messages.size());
for (int i = 0; i < messages.size(); i++) {
builders.add(null);
}
}
}
/**
* Gets the count of items in the list.
*
* @return the count of items in the list.
*/
public int getCount() {
return messages.size();
}
/**
* Gets whether the list is empty.
*
* @return whether the list is empty
*/
public boolean isEmpty() {
return messages.isEmpty();
}
/**
* Get the message at the specified index. If the message is currently stored as a {@code
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
* on it.
*
* @param index the index of the message to get
* @return the message for the specified index
*/
public MType getMessage(int index) {
return getMessage(index, false);
}
/**
* Get the message at the specified index. If the message is currently stored as a {@code
* Builder}, it is converted to a {@code Message} by calling {@link Message.Builder#buildPartial}
* on it.
*
* @param index the index of the message to get
* @param forBuild this is being called for build so we want to make sure we
* SingleFieldBuilder.build to send dirty invalidations
* @return the message for the specified index
*/
private MType getMessage(int index, boolean forBuild) {
if (this.builders == null) {
// We don't have any builders -- return the current Message.
// This is the case where no builder was created, so we MUST have a
// Message.
return messages.get(index);
}
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
// We don't have a builder -- return the current message.
// This is the case where no builder was created for the entry at index,
// so we MUST have a message.
return messages.get(index);
} else {
return forBuild ? builder.build() : builder.getMessage();
}
}
/**
* Gets a builder for the specified index. If no builder has been created for that index, a
* builder is created on demand by calling {@link Message#toBuilder}.
*
* @param index the index of the message to get
* @return The builder for that index
*/
public BType getBuilder(int index) {
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
MType message = messages.get(index);
builder = new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
builders.set(index, builder);
}
return builder.getBuilder();
}
/**
* Gets the base class interface for the specified index. This may either be a builder or a
* message. It will return whatever is more efficient.
*
* @param index the index of the message to get
* @return the message or builder for the index as the base class interface
*/
@SuppressWarnings("unchecked")
public IType getMessageOrBuilder(int index) {
if (this.builders == null) {
// We don't have any builders -- return the current Message.
// This is the case where no builder was created, so we MUST have a
// Message.
return (IType) messages.get(index);
}
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
// We don't have a builder -- return the current message.
// This is the case where no builder was created for the entry at index,
// so we MUST have a message.
return (IType) messages.get(index);
} else {
return builder.getMessageOrBuilder();
}
}
/**
* Sets a message at the specified index replacing the existing item at that index.
*
* @param index the index to set.
* @param message the message to set
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> setMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
messages.set(index, message);
if (builders != null) {
SingleFieldBuilder<MType, BType, IType> entry = builders.set(index, null);
if (entry != null) {
entry.dispose();
}
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends the specified element to the end of this list.
*
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addMessage(MType message) {
checkNotNull(message);
ensureMutableMessageList();
messages.add(message);
if (builders != null) {
builders.add(null);
}
onChanged();
incrementModCounts();
return this;
}
/**
* Inserts the specified message at the specified position in this list. Shifts the element
* currently at that position (if any) and any subsequent elements to the right (adds one to their
* indices).
*
* @param index the index at which to insert the message
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
messages.add(index, message);
if (builders != null) {
builders.add(index, null);
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends all of the messages in the specified collection to the end of this list, in the order
* that they are returned by the specified collection's iterator.
*
* @param values the messages to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {
checkNotNull(value);
}
// If we can inspect the size, we can more efficiently add messages.
int size = -1;
if (values instanceof Collection) {
final Collection<?> collection = (Collection<?>) values;
if (collection.isEmpty()) {
return this;
}
size = collection.size();
}
ensureMutableMessageList();
if (size >= 0 && messages instanceof ArrayList) {
((ArrayList<MType>) messages).ensureCapacity(messages.size() + size);
}
for (MType value : values) {
addMessage(value);
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends a new builder to the end of this list and returns the builder.
*
* @param message the message to add which is the basis of the builder
* @return the new builder
*/
public BType addBuilder(MType message) {
ensureMutableMessageList();
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder =
new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
messages.add(null);
builders.add(builder);
onChanged();
incrementModCounts();
return builder.getBuilder();
}
/**
* Inserts a new builder at the specified position in this list. Shifts the element currently at
* that position (if any) and any subsequent elements to the right (adds one to their indices).
*
* @param index the index at which to insert the builder
* @param message the message to add which is the basis of the builder
* @return the builder
*/
public BType addBuilder(int index, MType message) {
ensureMutableMessageList();
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder =
new SingleFieldBuilder<MType, BType, IType>(message, this, isClean);
messages.add(index, null);
builders.add(index, builder);
onChanged();
incrementModCounts();
return builder.getBuilder();
}
/**
* Removes the element at the specified position in this list. Shifts any subsequent elements to
* the left (subtracts one from their indices).
*
* @param index the index at which to remove the message
*/
public void remove(int index) {
ensureMutableMessageList();
messages.remove(index);
if (builders != null) {
SingleFieldBuilder<MType, BType, IType> entry = builders.remove(index);
if (entry != null) {
entry.dispose();
}
}
onChanged();
incrementModCounts();
}
/** Removes all of the elements from this list. The list will be empty after this call returns. */
public void clear() {
messages = Collections.emptyList();
isMessagesListMutable = false;
if (builders != null) {
for (SingleFieldBuilder<MType, BType, IType> entry : builders) {
if (entry != null) {
entry.dispose();
}
}
builders = null;
}
onChanged();
incrementModCounts();
}
/**
* Builds the list of messages from the builder and returns them.
*
* @return an immutable list of messages
*/
public List<MType> build() {
// Now that build has been called, we are required to dispatch
// invalidations.
isClean = true;
if (!isMessagesListMutable && builders == null) {
// We still have an immutable list and we never created a builder.
return messages;
}
boolean allMessagesInSync = true;
if (!isMessagesListMutable) {
// We still have an immutable list. Let's see if any of them are out
// of sync with their builders.
for (int i = 0; i < messages.size(); i++) {
Message message = messages.get(i);
SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
if (builder != null) {
if (builder.build() != message) {
allMessagesInSync = false;
break;
}
}
}
if (allMessagesInSync) {
// Immutable list is still in sync.
return messages;
}
}
// Need to make sure messages is up to date
ensureMutableMessageList();
for (int i = 0; i < messages.size(); i++) {
messages.set(i, getMessage(i, true));
}
// We're going to return our list as immutable so we mark that we can
// no longer update it.
messages = Collections.unmodifiableList(messages);
isMessagesListMutable = false;
return messages;
}
/**
* Gets a view of the builder as a list of messages. The returned list is live and will reflect
* any changes to the underlying builder.
*
* @return the messages in the list
*/
public List<MType> getMessageList() {
if (externalMessageList == null) {
externalMessageList = new MessageExternalList<MType, BType, IType>(this);
}
return externalMessageList;
}
/**
* Gets a view of the builder as a list of builders. This returned list is live and will reflect
* any changes to the underlying builder.
*
* @return the builders in the list
*/
public List<BType> getBuilderList() {
if (externalBuilderList == null) {
externalBuilderList = new BuilderExternalList<MType, BType, IType>(this);
}
return externalBuilderList;
}
/**
* Gets a view of the builder as a list of MessageOrBuilders. This returned list is live and will
* reflect any changes to the underlying builder.
*
* @return the builders in the list
*/
public List<IType> getMessageOrBuilderList() {
if (externalMessageOrBuilderList == null) {
externalMessageOrBuilderList = new MessageOrBuilderExternalList<MType, BType, IType>(this);
}
return externalMessageOrBuilderList;
}
/**
* Called when a the builder or one of its nested children has changed and any parent should be
* notified of its invalidation.
*/
private void onChanged() {
if (isClean && parent != null) {
parent.markDirty();
// Don't keep dispatching invalidations until build is called again.
isClean = false;
}
}
@Override
public void markDirty() {
onChanged();
}
/**
* Increments the mod counts so that an ConcurrentModificationException can be thrown if calling
* code tries to modify the builder while its iterating the list.
*/
private void incrementModCounts() {
if (externalMessageList != null) {
externalMessageList.incrementModCount();
}
if (externalBuilderList != null) {
externalBuilderList.incrementModCount();
}
if (externalMessageOrBuilderList != null) {
externalMessageOrBuilderList.incrementModCount();
}
}
/**
* Provides a live view of the builder as a list of messages.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class MessageExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<MType> implements List<MType>, RandomAccess {
RepeatedFieldBuilder<MType, BType, IType> builder;
MessageExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
@Override
public int size() {
return this.builder.getCount();
}
@Override
public MType get(int index) {
return builder.getMessage(index);
}
void incrementModCount() {
modCount++;
}
}
/**
* Provides a live view of the builder as a list of builders.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class BuilderExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<BType> implements List<BType>, RandomAccess {
RepeatedFieldBuilder<MType, BType, IType> builder;
BuilderExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
@Override
public int size() {
return this.builder.getCount();
}
@Override
public BType get(int index) {
return builder.getBuilder(index);
}
void incrementModCount() {
modCount++;
}
}
/**
* Provides a live view of the builder as a list of builders.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class MessageOrBuilderExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<IType> implements List<IType>, RandomAccess {
RepeatedFieldBuilder<MType, BType, IType> builder;
MessageOrBuilderExternalList(RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
@Override
public int size() {
return this.builder.getCount();
}
@Override
public IType get(int index) {
return builder.getMessageOrBuilder(index);
}
void incrementModCount() {
modCount++;
}
}
}

Some files were not shown because too many files have changed in this diff Show More