Merge remote-tracking branch 'remotes/upstream/master' into kotlinProtos
diff --git a/BUILD b/BUILD
index 07ee629..46d284e 100644
--- a/BUILD
+++ b/BUILD
@@ -401,6 +401,7 @@
"src/google/protobuf/compiler/java/java_generator.cc",
"src/google/protobuf/compiler/java/java_generator_factory.cc",
"src/google/protobuf/compiler/java/java_helpers.cc",
+ "src/google/protobuf/compiler/java/java_kotlin_generator.cc",
"src/google/protobuf/compiler/java/java_map_field.cc",
"src/google/protobuf/compiler/java/java_map_field_lite.cc",
"src/google/protobuf/compiler/java/java_message.cc",
diff --git a/Makefile.am b/Makefile.am
index 9151842..3f94f85 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -530,6 +530,35 @@
java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto \
java/core/src/test/proto/com/google/protobuf/test_custom_options.proto \
java/core/src/test/proto/com/google/protobuf/wrappers_test.proto \
+ java/kotlin/generate-sources-build.xml \
+ java/kotlin/generate-test-sources-build.xml \
+ java/kotlin/pom.xml \
+ java/kotlin/src/main/kotlin/com/google/protobuf/DslList.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/DslMap.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/DslProxy.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt\
+ java/kotlin/src/main/kotlin/com/google/protobuf/ExtensionList.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt\
+ java/kotlin/src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt \
+ java/kotlin/src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt \
+ java/kotlin/src/test/kotlin/com/google/protobuf/DslListTest.kt \
+ java/kotlin/src/test/kotlin/com/google/protobuf/DslMapTest.kt \
+ java/kotlin/src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt\
+ java/kotlin/src/test/kotlin/com/google/protobuf/ExtensionListTest.kt \
+ java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt \
+ java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt \
+ java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto2.proto \
+ java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto3.proto \
+ java/kotlin/src/test/proto/com/google/protobuf/example_extensible_message.proto \
+ java/kotlin/src/test/proto/com/google/protobuf/multiple_files_proto3.proto \
+ java/kotlin-lite/generate-sources-build.xml \
+ java/kotlin-lite/generate-test-sources-build.xml \
+ java/kotlin-lite/lite.awk \
+ java/kotlin-lite/pom.xml \
+ java/kotlin-lite/process-lite-sources-build.xml \
+ java/kotlin-lite/src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt\
+ java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt \
java/lite.md \
java/lite/BUILD \
java/lite/generate-sources-build.xml \
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index 5c5799e..ad630af 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -26,6 +26,7 @@
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h" include\google\protobuf\compiler\csharp\csharp_names.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h" include\google\protobuf\compiler\importer.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h" include\google\protobuf\compiler\java\java_generator.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_kotlin_generator.h" include\google\protobuf\compiler\java\java_kotlin_generator.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_names.h" include\google\protobuf\compiler\java\java_names.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\js\js_generator.h" include\google\protobuf\compiler\js\js_generator.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\js\well_known_types_embed.h" include\google\protobuf\compiler\js\well_known_types_embed.h
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index ecb5a85..6316d83 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -44,6 +44,7 @@
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator_factory.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_helpers.cc
+ ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_kotlin_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_map_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_map_field_lite.cc
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message.cc
diff --git a/java/kotlin-lite/generate-sources-build.xml b/java/kotlin-lite/generate-sources-build.xml
new file mode 100644
index 0000000..74d96a2
--- /dev/null
+++ b/java/kotlin-lite/generate-sources-build.xml
@@ -0,0 +1,19 @@
+<project name="generate-sources">
+ <echo message="Running protoc ..."/>
+ <mkdir dir="${generated.sources.dir}"/>
+ <exec executable="${protoc}">
+ <arg value="--java_out=lite:${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/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"/>
+ </exec>
+</project>
+
diff --git a/java/kotlin-lite/generate-test-sources-build.xml b/java/kotlin-lite/generate-test-sources-build.xml
new file mode 100644
index 0000000..c5f60b8
--- /dev/null
+++ b/java/kotlin-lite/generate-test-sources-build.xml
@@ -0,0 +1,34 @@
+<project name="generate-test-sources">
+ <mkdir dir="${generated.testsources.dir}"/>
+ <exec executable="${protoc}">
+ <arg value="--java_out=lite:${generated.testsources.dir}"/>
+ <arg value="--proto_path=${protobuf.source.dir}"/>
+ <arg value="--proto_path=${protobuf.basedir}/java/kotlin/${test.proto.dir}"/>
+ <arg value="--experimental_allow_proto3_optional"/>
+ <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_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_proto3.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/example_extensible_message.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/multiple_files_proto3.proto"/>
+ </exec>
+ <exec executable="${protoc}">
+ <arg value="--kotlin_out=lite:${generated.testsources.dir}"/>
+ <arg value="--proto_path=${protobuf.source.dir}"/>
+ <arg value="--proto_path=${protobuf.basedir}/java/kotlin/${test.proto.dir}"/>
+ <arg value="--experimental_allow_proto3_optional"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/map_lite_unittest.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/example_extensible_message.proto"/>
+ <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/multiple_files_proto3.proto"/>
+ </exec>
+</project>
diff --git a/java/kotlin-lite/lite.awk b/java/kotlin-lite/lite.awk
new file mode 100644
index 0000000..b22d965
--- /dev/null
+++ b/java/kotlin-lite/lite.awk
@@ -0,0 +1,25 @@
+# Remove code enclosed by "BEGIN FULL-RUNTIME" and "END FULL-RUNTIME" to
+# create the lite-only version of a test file.
+
+BEGIN {
+ in_full_runtime = 0;
+}
+
+/BEGIN FULL-RUNTIME/ {
+ in_full_runtime = 1;
+ next;
+}
+
+/END FULL-RUNTIME/ {
+ in_full_runtime = 0;
+ next;
+}
+
+in_full_runtime {
+ # Skip full runtime code path.
+ next;
+}
+
+{
+ print;
+}
diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml
new file mode 100644
index 0000000..1d75251
--- /dev/null
+++ b/java/kotlin-lite/pom.xml
@@ -0,0 +1,383 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-parent</artifactId>
+ <version>3.15.6</version>
+ </parent>
+
+ <artifactId>protobuf-kotlin-lite</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Protocol Buffers [Lite]</name>
+ <description>
+ Lite version of Protocol Buffers library. This version is optimized for code size, but does
+ not guarantee API/ABI stability.
+ </description>
+
+ <properties>
+ <kotlin.version>1.4.31</kotlin.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib</artifactId>
+ <version>${kotlin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-test</artifactId>
+ <version>${kotlin.version}</version>
+ </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/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>
+ </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>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-source-files</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.sources.dir}/com/google/protobuf</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../core/src/main/java/com/google/protobuf</directory>
+ <includes>
+ <!-- Keep in sync with //java/core:BUILD -->
+ <include>AbstractMessageLite.java</include>
+ <include>AbstractParser.java</include>
+ <include>AbstractProtobufList.java</include>
+ <include>AllocatedBuffer.java</include>
+ <include>Android.java</include>
+ <include>ArrayDecoders.java</include>
+ <include>BinaryReader.java</include>
+ <include>BinaryWriter.java</include>
+ <include>BooleanArrayList.java</include>
+ <include>BufferAllocator.java</include>
+ <include>ByteBufferWriter.java</include>
+ <include>ByteOutput.java</include>
+ <include>ByteString.java</include>
+ <include>CodedInputStream.java</include>
+ <include>CodedInputStreamReader.java</include>
+ <include>CodedOutputStream.java</include>
+ <include>CodedOutputStreamWriter.java</include>
+ <include>DoubleArrayList.java</include>
+ <include>ExperimentalApi.java</include>
+ <include>ExtensionLite.java</include>
+ <include>ExtensionRegistryFactory.java</include>
+ <include>ExtensionRegistryLite.java</include>
+ <include>ExtensionSchema.java</include>
+ <include>ExtensionSchemaLite.java</include>
+ <include>ExtensionSchemas.java</include>
+ <include>FieldInfo.java</include>
+ <include>FieldSet.java</include>
+ <include>FieldType.java</include>
+ <include>FloatArrayList.java</include>
+ <include>GeneratedMessageInfoFactory.java</include>
+ <include>GeneratedMessageLite.java</include>
+ <include>IntArrayList.java</include>
+ <include>Internal.java</include>
+ <include>InvalidProtocolBufferException.java</include>
+ <include>IterableByteBufferInputStream.java</include>
+ <include>JavaType.java</include>
+ <include>LazyField.java</include>
+ <include>LazyFieldLite.java</include>
+ <include>LazyStringArrayList.java</include>
+ <include>LazyStringList.java</include>
+ <include>ListFieldSchema.java</include>
+ <include>LongArrayList.java</include>
+ <include>ManifestSchemaFactory.java</include>
+ <include>MapEntryLite.java</include>
+ <include>MapFieldLite.java</include>
+ <include>MapFieldSchema.java</include>
+ <include>MapFieldSchemaLite.java</include>
+ <include>MapFieldSchemas.java</include>
+ <include>MessageInfo.java</include>
+ <include>MessageInfoFactory.java</include>
+ <include>MessageLite.java</include>
+ <include>MessageLiteOrBuilder.java</include>
+ <include>MessageLiteToString.java</include>
+ <include>MessageSchema.java</include>
+ <include>MessageSetSchema.java</include>
+ <include>MutabilityOracle.java</include>
+ <include>NewInstanceSchema.java</include>
+ <include>NewInstanceSchemaLite.java</include>
+ <include>NewInstanceSchemas.java</include>
+ <include>NioByteString.java</include>
+ <include>OneofInfo.java</include>
+ <include>Parser.java</include>
+ <include>PrimitiveNonBoxingCollection.java</include>
+ <include>ProtoSyntax.java</include>
+ <include>Protobuf.java</include>
+ <include>ProtobufArrayList.java</include>
+ <include>ProtobufLists.java</include>
+ <include>ProtocolStringList.java</include>
+ <include>RawMessageInfo.java</include>
+ <include>Reader.java</include>
+ <include>RopeByteString.java</include>
+ <include>Schema.java</include>
+ <include>SchemaFactory.java</include>
+ <include>SchemaUtil.java</include>
+ <include>SmallSortedMap.java</include>
+ <include>StructuralMessageInfo.java</include>
+ <include>TextFormatEscaper.java</include>
+ <include>UninitializedMessageException.java</include>
+ <include>UnknownFieldSchema.java</include>
+ <include>UnknownFieldSetLite.java</include>
+ <include>UnknownFieldSetLiteSchema.java</include>
+ <include>UnmodifiableLazyStringList.java</include>
+ <include>UnsafeUtil.java</include>
+ <include>Utf8.java</include>
+ <include>WireFormat.java</include>
+ <include>Writer.java</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-kotlin-source-files</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.sources.dir}/com/google/protobuf</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../kotlin/src/main/kotlin/com/google/protobuf</directory>
+ <includes>
+ <include>DslList.kt</include>
+ <include>DslMap.kt</include>
+ <include>DslProxy.kt</include>
+ <include>ExtendableMessageLiteExtensions.kt</include>
+ <include>ExtensionList.kt</include>
+ <include>OnlyForUseByGeneratedProtoCode.kt</include>
+ <include>ProtoDslMarker.kt</include>
+ <include>UnmodifiableCollections.kt</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-test-source-files</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.testsources.dir}/com/google/protobuf</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../core/src/test/java/com/google/protobuf</directory>
+ <includes>
+ <include>TestUtilLite.java</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${basedir}/../kotlin/src/test/kotlin/com/google/protobuf</directory>
+ <excludes>
+ <exclude>ExtendableMessageExtensionsTest.kt</exclude>
+ <exclude>Proto2Test.kt</exclude>
+ <exclude>ProtoUtil.java</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- 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>
+
+ <execution>
+ <id>process-lite-sources</id>
+ <phase>generate-test-sources</phase>
+ <configuration>
+ <target>
+ <ant antfile="process-lite-sources-build.xml"/>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <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>
+
+ <plugin>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-maven-plugin</artifactId>
+ <version>${kotlin.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>compile</id>
+ <goals> <goal>compile</goal> </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${generated.sources.dir}</sourceDir>
+ <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
+ </sourceDirs>
+ </configuration>
+ </execution>
+ <execution>
+ <id>test-compile</id>
+ <goals> <goal>test-compile</goal> </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
+ <sourceDir>${generated.testsources.dir}</sourceDir>
+ </sourceDirs>
+ </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>
diff --git a/java/kotlin-lite/process-lite-sources-build.xml b/java/kotlin-lite/process-lite-sources-build.xml
new file mode 100644
index 0000000..d49cf3a
--- /dev/null
+++ b/java/kotlin-lite/process-lite-sources-build.xml
@@ -0,0 +1,7 @@
+<project name="process-lite-sources">
+ <exec executable="awk" output="${generated.testsources.dir}/com/google/protobuf/TestUtil.java">
+ <arg value="-f" />
+ <arg value="${basedir}/lite.awk" />
+ <arg value="${basedir}/../core/src/test/java/com/google/protobuf/TestUtil.java" />
+ </exec>
+</project>
diff --git a/java/kotlin-lite/src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt
new file mode 100644
index 0000000..18933d1
--- /dev/null
+++ b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt
@@ -0,0 +1,60 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import example_extensible_message.ExampleExtensibleMessage
+import example_extensible_message.ExampleExtensibleMessageOuterClass as TestProto
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtendableMessageLiteExtensionsTest {
+ @Test
+ fun setOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ builder[TestProto.int32Extension] = 5
+ assertThat(builder.build().getExtension(TestProto.int32Extension)).isEqualTo(5)
+ }
+
+ @Test
+ fun getOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(builder[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun getOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(message[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun containsPositiveOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(TestProto.int32Extension in message).isTrue()
+ }
+
+ @Test
+ fun containsPositiveOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(TestProto.int32Extension in builder).isTrue()
+ }
+
+ @Test
+ fun containsNegativeOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder().build()
+ assertThat(TestProto.int32Extension in message).isFalse()
+ }
+
+ @Test
+ fun containsNegativeOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ assertThat(TestProto.int32Extension in builder).isFalse()
+ }
+}
diff --git a/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt
new file mode 100644
index 0000000..8726bbf
--- /dev/null
+++ b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt
@@ -0,0 +1,993 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.TestAllTypesLiteKt
+import com.google.protobuf.TestAllTypesLiteKt.nestedMessage
+import com.google.protobuf.TestUtilLite
+import com.google.protobuf.TestUtilLite.toBytes
+import com.google.protobuf.UnittestImportLite.ImportEnumLite
+import com.google.protobuf.UnittestImportLite.ImportMessageLite
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite
+import com.google.protobuf.UnittestLite
+import com.google.protobuf.UnittestLite.ForeignEnumLite
+import com.google.protobuf.UnittestLite.TestAllTypesLite
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum
+import com.google.protobuf.UnittestLite.TestEmptyMessageLite
+import com.google.protobuf.UnittestLite.TestEmptyMessageWithExtensionsLite
+import com.google.protobuf.copy
+import com.google.protobuf.foreignMessageLite
+import evil_names_proto2.EvilNamesProto2OuterClass.EvilNamesProto2
+import evil_names_proto2.EvilNamesProto2OuterClass.HardKeywordsAllTypes
+import evil_names_proto2.EvilNamesProto2OuterClass.Interface
+import evil_names_proto2.HardKeywordsAllTypesKt
+import evil_names_proto2.evilNamesProto2
+import evil_names_proto2.hardKeywordsAllTypes
+import evil_names_proto2.interface_
+import com.google.protobuf.optionalGroupExtensionLite
+import com.google.protobuf.repeatedGroupExtensionLite
+import com.google.protobuf.testAllExtensionsLite
+import com.google.protobuf.testAllTypesLite
+import com.google.protobuf.testEmptyMessageLite
+import com.google.protobuf.testEmptyMessageWithExtensionsLite
+import protobuf_unittest.MapLiteUnittest.MapEnumLite
+import protobuf_unittest.MapLiteUnittest.TestMapLite
+import protobuf_unittest.testMapLite
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto2LiteTest {
+ @Test
+ fun testSetters() {
+ assertThat(
+ testAllTypesLite {
+ optionalInt32 = 101
+ optionalInt64 = 102
+ optionalUint32 = 103
+ optionalUint64 = 104
+ optionalSint32 = 105
+ optionalSint64 = 106
+ optionalFixed32 = 107
+ optionalFixed64 = 108
+ optionalSfixed32 = 109
+ optionalSfixed64 = 110
+ optionalFloat = 111.0f
+ optionalDouble = 112.0
+ optionalBool = true
+ optionalString = "115"
+ optionalBytes = toBytes("116")
+ optionalGroup =
+ TestAllTypesLiteKt.optionalGroup { a = 117 }
+ optionalNestedMessage = nestedMessage { bb = 118 }
+ optionalForeignMessage =
+ foreignMessageLite { c = 119 }
+ optionalImportMessage =
+ ImportMessageLite.newBuilder().setD(120).build()
+ optionalPublicImportMessage =
+ PublicImportMessageLite.newBuilder().setE(126).build()
+ optionalLazyMessage = nestedMessage { bb = 127 }
+ optionalNestedEnum = NestedEnum.BAZ
+ optionalForeignEnum = ForeignEnumLite.FOREIGN_LITE_BAZ
+ optionalImportEnum = ImportEnumLite.IMPORT_LITE_BAZ
+ optionalStringPiece = "124"
+ optionalCord = "125"
+ repeatedInt32.add(201)
+ repeatedInt64.add(202)
+ repeatedUint32.add(203)
+ repeatedUint64.add(204)
+ repeatedSint32.add(205)
+ repeatedSint64.add(206)
+ repeatedFixed32.add(207)
+ repeatedFixed64.add(208)
+ repeatedSfixed32.add(209)
+ repeatedSfixed64.add(210)
+ repeatedFloat.add(211f)
+ repeatedDouble.add(212.0)
+ repeatedBool.add(true)
+ repeatedString.add("215")
+ repeatedBytes.add(toBytes("216"))
+ repeatedGroup.add(TestAllTypesLiteKt.repeatedGroup { a = 217 })
+ repeatedNestedMessage.add(nestedMessage { bb = 218 })
+ repeatedForeignMessage.add(
+ foreignMessageLite { c = 219 }
+ )
+ repeatedImportMessage.add(
+ ImportMessageLite.newBuilder().setD(220).build()
+ )
+ repeatedLazyMessage.add(nestedMessage { bb = 227 })
+ repeatedNestedEnum.add(NestedEnum.BAR)
+ repeatedForeignEnum.add(ForeignEnumLite.FOREIGN_LITE_BAR)
+ repeatedImportEnum.add(ImportEnumLite.IMPORT_LITE_BAR)
+ repeatedStringPiece.add("224")
+ repeatedCord.add("225")
+ repeatedInt32 += 301
+ repeatedInt64 += 302
+ repeatedUint32 += 303
+ repeatedUint64 += 304
+ repeatedSint32 += 305
+ repeatedSint64 += 306
+ repeatedFixed32 += 307
+ repeatedFixed64 += 308
+ repeatedSfixed32 += 309
+ repeatedSfixed64 += 310
+ repeatedFloat += 311f
+ repeatedDouble += 312.0
+ repeatedBool += false
+ repeatedString += "315"
+ repeatedBytes += toBytes("316")
+ repeatedGroup += TestAllTypesLiteKt.repeatedGroup { a = 317 }
+ repeatedNestedMessage += nestedMessage { bb = 318 }
+ repeatedForeignMessage +=
+ foreignMessageLite { c = 319 }
+ repeatedImportMessage +=
+ ImportMessageLite.newBuilder().setD(320).build()
+ repeatedLazyMessage +=
+ TestAllTypesLiteKt.nestedMessage { bb = 327 }
+ repeatedNestedEnum += NestedEnum.BAZ
+ repeatedForeignEnum += ForeignEnumLite.FOREIGN_LITE_BAZ
+ repeatedImportEnum += ImportEnumLite.IMPORT_LITE_BAZ
+ repeatedStringPiece += "324"
+ repeatedCord += "325"
+ defaultInt32 = 401
+ defaultInt64 = 402
+ defaultUint32 = 403
+ defaultUint64 = 404
+ defaultSint32 = 405
+ defaultSint64 = 406
+ defaultFixed32 = 407
+ defaultFixed64 = 408
+ defaultSfixed32 = 409
+ defaultSfixed64 = 410
+ defaultFloat = 411f
+ defaultDouble = 412.0
+ defaultBool = false
+ defaultString = "415"
+ defaultBytes = toBytes("416")
+ defaultNestedEnum = NestedEnum.FOO
+ defaultForeignEnum = ForeignEnumLite.FOREIGN_LITE_FOO
+ defaultImportEnum = ImportEnumLite.IMPORT_LITE_FOO
+ defaultStringPiece = "424"
+ defaultCord = "425"
+ oneofUint32 = 601
+ oneofNestedMessage =
+ TestAllTypesLiteKt.nestedMessage { bb = 602 }
+ oneofString = "603"
+ oneofBytes = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtilLite.getAllLiteSetBuilder().build()
+ )
+ }
+
+ @Test
+ fun testGetters() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ assertThat(optionalGroup).isEqualTo(TestAllTypesLiteKt.optionalGroup { a = 117 })
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesLiteKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ defaultInt32 = 401
+ assertThat(defaultInt32).isEqualTo(401)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testDefaultGetters() {
+ testAllTypesLite {
+ assertThat(defaultInt32).isEqualTo(41)
+ assertThat(defaultString).isEqualTo("hello")
+ assertThat(defaultNestedEnum).isEqualTo(NestedEnum.BAR)
+ assertThat(defaultStringPiece).isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypesLite {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedGroup.addAll(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 }
+ )
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 }
+ )
+ )
+ repeatedGroup +=
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 },
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ )
+ repeatedGroup[0] = TestAllTypesLiteKt.repeatedGroup { a = 5 }
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 5 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 },
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ )
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testHazzers() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ assertThat(hasOptionalInt32()).isTrue()
+ assertThat(hasOptionalString()).isFalse()
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ assertThat(hasOptionalGroup()).isTrue()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(hasOptionalNestedEnum()).isTrue()
+ assertThat(hasDefaultInt32()).isFalse()
+ oneofUint32 = 601
+ assertThat(hasOneofUint32()).isTrue()
+ }
+
+ testAllTypesLite {
+ assertThat(hasOptionalInt32()).isFalse()
+ optionalString = "115"
+ assertThat(hasOptionalString()).isTrue()
+ assertThat(hasOptionalGroup()).isFalse()
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(hasOptionalNestedMessage()).isTrue()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+ defaultInt32 = 401
+ assertThat(hasDefaultInt32()).isTrue()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testClears() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ clearOptionalInt32()
+ assertThat(hasOptionalInt32()).isFalse()
+
+ optionalString = "115"
+ clearOptionalString()
+ assertThat(hasOptionalString()).isFalse()
+
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ clearOptionalGroup()
+ assertThat(hasOptionalGroup()).isFalse()
+
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+
+ defaultInt32 = 401
+ clearDefaultInt32()
+ assertThat(hasDefaultInt32()).isFalse()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypesLite {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypesLite {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(hasOneofUint32()).isFalse()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testExtensionsSet() {
+ assertThat(
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ this[UnittestLite.optionalInt64ExtensionLite] = 102L
+ this[UnittestLite.optionalUint32ExtensionLite] = 103
+ this[UnittestLite.optionalUint64ExtensionLite] = 104L
+ this[UnittestLite.optionalSint32ExtensionLite] = 105
+ this[UnittestLite.optionalSint64ExtensionLite] = 106L
+ this[UnittestLite.optionalFixed32ExtensionLite] = 107
+ this[UnittestLite.optionalFixed64ExtensionLite] = 108L
+ this[UnittestLite.optionalSfixed32ExtensionLite] = 109
+ this[UnittestLite.optionalSfixed64ExtensionLite] = 110L
+ this[UnittestLite.optionalFloatExtensionLite] = 111F
+ this[UnittestLite.optionalDoubleExtensionLite] = 112.0
+ this[UnittestLite.optionalBoolExtensionLite] = true
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ this[UnittestLite.optionalBytesExtensionLite] = toBytes("116")
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ this[UnittestLite.optionalForeignMessageExtensionLite] = foreignMessageLite { c = 119 }
+ this[UnittestLite.optionalImportMessageExtensionLite] =
+ ImportMessageLite.newBuilder().setD(120).build()
+ this[UnittestLite.optionalPublicImportMessageExtensionLite] =
+ PublicImportMessageLite.newBuilder().setE(126).build()
+ this[UnittestLite.optionalLazyMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 127 }
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ this[UnittestLite.optionalForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_BAZ
+ this[UnittestLite.optionalImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_BAZ
+ this[UnittestLite.optionalStringPieceExtensionLite] = "124"
+ this[UnittestLite.optionalCordExtensionLite] = "125"
+ this[UnittestLite.repeatedInt32ExtensionLite].add(201)
+ this[UnittestLite.repeatedInt64ExtensionLite].add(202L)
+ this[UnittestLite.repeatedUint32ExtensionLite].add(203)
+ this[UnittestLite.repeatedUint64ExtensionLite].add(204L)
+ this[UnittestLite.repeatedSint32ExtensionLite].add(205)
+ this[UnittestLite.repeatedSint64ExtensionLite].add(206L)
+ this[UnittestLite.repeatedFixed32ExtensionLite].add(207)
+ this[UnittestLite.repeatedFixed64ExtensionLite].add(208L)
+ this[UnittestLite.repeatedSfixed32ExtensionLite].add(209)
+ this[UnittestLite.repeatedSfixed64ExtensionLite].add(210L)
+ this[UnittestLite.repeatedFloatExtensionLite].add(211F)
+ this[UnittestLite.repeatedDoubleExtensionLite].add(212.0)
+ this[UnittestLite.repeatedBoolExtensionLite].add(true)
+ this[UnittestLite.repeatedStringExtensionLite].add("215")
+ this[UnittestLite.repeatedBytesExtensionLite].add(toBytes("216"))
+ this[UnittestLite.repeatedGroupExtensionLite].add(repeatedGroupExtensionLite { a = 217 })
+ this[UnittestLite.repeatedNestedMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 218 }
+ )
+ this[UnittestLite.repeatedForeignMessageExtensionLite].add(foreignMessageLite { c = 219 })
+ this[UnittestLite.repeatedImportMessageExtensionLite].add(
+ ImportMessageLite.newBuilder().setD(220).build()
+ )
+ this[UnittestLite.repeatedLazyMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 227 }
+ )
+ this[UnittestLite.repeatedNestedEnumExtensionLite].add(NestedEnum.BAR)
+ this[UnittestLite.repeatedForeignEnumExtensionLite].add(ForeignEnumLite.FOREIGN_LITE_BAR)
+ this[UnittestLite.repeatedImportEnumExtensionLite].add(ImportEnumLite.IMPORT_LITE_BAR)
+ this[UnittestLite.repeatedStringPieceExtensionLite].add("224")
+ this[UnittestLite.repeatedCordExtensionLite].add("225")
+ this[UnittestLite.repeatedInt32ExtensionLite].add(301)
+ this[UnittestLite.repeatedInt64ExtensionLite].add(302L)
+ this[UnittestLite.repeatedUint32ExtensionLite].add(303)
+ this[UnittestLite.repeatedUint64ExtensionLite].add(304L)
+ this[UnittestLite.repeatedSint32ExtensionLite].add(305)
+ this[UnittestLite.repeatedSint64ExtensionLite].add(306L)
+ this[UnittestLite.repeatedFixed32ExtensionLite].add(307)
+ this[UnittestLite.repeatedFixed64ExtensionLite].add(308L)
+ this[UnittestLite.repeatedSfixed32ExtensionLite].add(309)
+ this[UnittestLite.repeatedSfixed64ExtensionLite].add(310L)
+ this[UnittestLite.repeatedFloatExtensionLite].add(311F)
+ this[UnittestLite.repeatedDoubleExtensionLite].add(312.0)
+ this[UnittestLite.repeatedBoolExtensionLite].add(false)
+ this[UnittestLite.repeatedStringExtensionLite].add("315")
+ this[UnittestLite.repeatedBytesExtensionLite].add(toBytes("316"))
+ this[UnittestLite.repeatedGroupExtensionLite].add(repeatedGroupExtensionLite { a = 317 })
+ this[UnittestLite.repeatedNestedMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 318 }
+ )
+ this[UnittestLite.repeatedForeignMessageExtensionLite].add(foreignMessageLite { c = 319 })
+ this[UnittestLite.repeatedImportMessageExtensionLite].add(
+ ImportMessageLite.newBuilder().setD(320).build()
+ )
+ this[UnittestLite.repeatedLazyMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 327 }
+ )
+ this[UnittestLite.repeatedNestedEnumExtensionLite].add(NestedEnum.BAZ)
+ this[UnittestLite.repeatedForeignEnumExtensionLite].add(ForeignEnumLite.FOREIGN_LITE_BAZ)
+ this[UnittestLite.repeatedImportEnumExtensionLite].add(ImportEnumLite.IMPORT_LITE_BAZ)
+ this[UnittestLite.repeatedStringPieceExtensionLite].add("324")
+ this[UnittestLite.repeatedCordExtensionLite].add("325")
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ this[UnittestLite.defaultInt64ExtensionLite] = 402L
+ this[UnittestLite.defaultUint32ExtensionLite] = 403
+ this[UnittestLite.defaultUint64ExtensionLite] = 404L
+ this[UnittestLite.defaultSint32ExtensionLite] = 405
+ this[UnittestLite.defaultSint64ExtensionLite] = 406L
+ this[UnittestLite.defaultFixed32ExtensionLite] = 407
+ this[UnittestLite.defaultFixed64ExtensionLite] = 408L
+ this[UnittestLite.defaultSfixed32ExtensionLite] = 409
+ this[UnittestLite.defaultSfixed64ExtensionLite] = 410L
+ this[UnittestLite.defaultFloatExtensionLite] = 411F
+ this[UnittestLite.defaultDoubleExtensionLite] = 412.0
+ this[UnittestLite.defaultBoolExtensionLite] = false
+ this[UnittestLite.defaultStringExtensionLite] = "415"
+ this[UnittestLite.defaultBytesExtensionLite] = toBytes("416")
+ this[UnittestLite.defaultNestedEnumExtensionLite] = NestedEnum.FOO
+ this[UnittestLite.defaultForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_FOO
+ this[UnittestLite.defaultImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_FOO
+ this[UnittestLite.defaultStringPieceExtensionLite] = "424"
+ this[UnittestLite.defaultCordExtensionLite] = "425"
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ this[UnittestLite.oneofNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 602 }
+ this[UnittestLite.oneofStringExtensionLite] = "603"
+ this[UnittestLite.oneofBytesExtensionLite] = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtilLite.getAllLiteExtensionsSet()
+ )
+ }
+
+ @Test
+ fun testExtensionGetters() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ assertThat(this[UnittestLite.optionalInt32ExtensionLite]).isEqualTo(101)
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ assertThat(this[UnittestLite.optionalStringExtensionLite]).isEqualTo("115")
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ assertThat(this[UnittestLite.optionalGroupExtensionLite])
+ .isEqualTo(optionalGroupExtensionLite { a = 117 })
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(this[UnittestLite.optionalNestedMessageExtensionLite])
+ .isEqualTo(TestAllTypesLiteKt.nestedMessage { bb = 118 })
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ assertThat(this[UnittestLite.optionalNestedEnumExtensionLite]).isEqualTo(NestedEnum.BAZ)
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ assertThat(this[UnittestLite.defaultInt32ExtensionLite]).isEqualTo(401)
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ assertThat(this[UnittestLite.oneofUint32ExtensionLite]).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testRepeatedExtensionGettersAndSetters() {
+ testAllExtensionsLite {
+ this[UnittestLite.repeatedInt32ExtensionLite].addAll(listOf(1, 2))
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(1, 2))
+ this[UnittestLite.repeatedInt32ExtensionLite].addAll(listOf(3, 4))
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(1, 2, 3, 4))
+ this[UnittestLite.repeatedInt32ExtensionLite][0] = 5
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(5, 2, 3, 4))
+
+ this[UnittestLite.repeatedStringExtensionLite].addAll(listOf("1", "2"))
+ assertThat(this[UnittestLite.repeatedStringExtensionLite]).isEqualTo(listOf("1", "2"))
+ this[UnittestLite.repeatedStringExtensionLite].addAll(listOf("3", "4"))
+ assertThat(this[UnittestLite.repeatedStringExtensionLite])
+ .isEqualTo(listOf("1", "2", "3", "4"))
+ this[UnittestLite.repeatedStringExtensionLite][0] = "5"
+ assertThat(this[UnittestLite.repeatedStringExtensionLite])
+ .isEqualTo(listOf("5", "2", "3", "4"))
+
+ this[UnittestLite.repeatedGroupExtensionLite].addAll(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 }
+ )
+ )
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 }
+ )
+ )
+ this[UnittestLite.repeatedGroupExtensionLite].addAll(
+ listOf(
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ )
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 },
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ )
+ this[UnittestLite.repeatedGroupExtensionLite][0] = repeatedGroupExtensionLite { a = 5 }
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 5 },
+ repeatedGroupExtensionLite { a = 2 },
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ )
+
+ this[UnittestLite.repeatedNestedMessageExtensionLite].addAll(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ this[UnittestLite.repeatedNestedMessageExtensionLite].addAll(
+ listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ )
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ this[UnittestLite.repeatedNestedMessageExtensionLite][0] = nestedMessage { bb = 5 }
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ this[UnittestLite.repeatedNestedEnumExtensionLite]
+ .addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite])
+ .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ this[UnittestLite.repeatedNestedEnumExtensionLite].addAll(listOf(NestedEnum.BAZ, NestedEnum.FOO))
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ this[UnittestLite.repeatedNestedEnumExtensionLite][0] = NestedEnum.BAR
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testExtensionContains() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isFalse()
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isFalse()
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isFalse()
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isTrue()
+ }
+
+ testAllExtensionsLite {
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isFalse()
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isFalse()
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isFalse()
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isFalse()
+ }
+ }
+
+ @Test
+ fun testExtensionClears() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ clear(UnittestLite.optionalInt32ExtensionLite)
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ clear(UnittestLite.optionalStringExtensionLite)
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ clear(UnittestLite.optionalGroupExtensionLite)
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ clear(UnittestLite.optionalNestedMessageExtensionLite)
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ clear(UnittestLite.optionalNestedEnumExtensionLite)
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isFalse()
+
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ clear(UnittestLite.defaultInt32ExtensionLite)
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isFalse()
+
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ clear(UnittestLite.oneofUint32ExtensionLite)
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isFalse()
+ }
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessageLite {}
+ ).isEqualTo(
+ TestEmptyMessageLite.newBuilder().build()
+ )
+
+ assertThat(
+ testEmptyMessageWithExtensionsLite {}
+ ).isEqualTo(
+ TestEmptyMessageWithExtensionsLite.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testMapSetters() {
+ assertThat(
+ testMapLite {
+ mapInt32Int32[1] = 2
+ mapInt64Int64[1L] = 2L
+ mapUint32Uint32[1] = 2
+ mapUint64Uint64[1L] = 2L
+ mapSint32Sint32[1] = 2
+ mapSint64Sint64[1L] = 2L
+ mapFixed32Fixed32[1] = 2
+ mapFixed64Fixed64[1L] = 2L
+ mapSfixed32Sfixed32[1] = 2
+ mapSfixed64Sfixed64[1L] = 2L
+ mapInt32Float[1] = 2F
+ mapInt32Double[1] = 2.0
+ mapBoolBool[true] = true
+ mapStringString["1"] = "2"
+ mapInt32Bytes[1] = toBytes("2")
+ mapInt32Enum[1] = MapEnumLite.MAP_ENUM_FOO_LITE
+ mapInt32ForeignMessage[1] = foreignMessageLite { c = 1 }
+ }
+ ).isEqualTo(
+ TestMapLite.newBuilder()
+ .putMapInt32Int32(1, 2)
+ .putMapInt64Int64(1L, 2L)
+ .putMapUint32Uint32(1, 2)
+ .putMapUint64Uint64(1L, 2L)
+ .putMapSint32Sint32(1, 2)
+ .putMapSint64Sint64(1L, 2L)
+ .putMapFixed32Fixed32(1, 2)
+ .putMapFixed64Fixed64(1L, 2L)
+ .putMapSfixed32Sfixed32(1, 2)
+ .putMapSfixed64Sfixed64(1L, 2L)
+ .putMapInt32Float(1, 2F)
+ .putMapInt32Double(1, 2.0)
+ .putMapBoolBool(true, true)
+ .putMapStringString("1", "2")
+ .putMapInt32Bytes(1, toBytes("2"))
+ .putMapInt32Enum(1, MapEnumLite.MAP_ENUM_FOO_LITE)
+ .putMapInt32ForeignMessage(1, foreignMessageLite { c = 1 })
+ .build()
+ )
+ }
+
+ @Test
+ fun testMapGettersAndSetters() {
+ testMapLite {
+ mapInt32Int32.put(1, 2)
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2))
+ mapInt32Int32[3] = 4
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.putAll(mapOf(5 to 6, 7 to 8))
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2, 3 to 4, 5 to 6, 7 to 8))
+
+ mapStringString.put("1", "2")
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2"))
+ mapStringString["3"] = "4"
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2", "3" to "4"))
+ mapStringString.putAll(mapOf("5" to "6", "7" to "8"))
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2", "3" to "4", "5" to "6", "7" to "8"))
+
+ mapInt32Enum.put(1, MapEnumLite.MAP_ENUM_FOO_LITE)
+ assertThat(mapInt32Enum).isEqualTo(mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE))
+ mapInt32Enum[2] = MapEnumLite.MAP_ENUM_BAR_LITE
+ assertThat(mapInt32Enum).isEqualTo(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.putAll(
+ mapOf(3 to MapEnumLite.MAP_ENUM_BAZ_LITE, 4 to MapEnumLite.MAP_ENUM_FOO_LITE)
+ )
+ assertThat(mapInt32Enum).isEqualTo(
+ mapOf(
+ 1 to MapEnumLite.MAP_ENUM_FOO_LITE,
+ 2 to MapEnumLite.MAP_ENUM_BAR_LITE,
+ 3 to MapEnumLite.MAP_ENUM_BAZ_LITE,
+ 4 to MapEnumLite.MAP_ENUM_FOO_LITE
+ )
+ )
+
+ mapInt32ForeignMessage.put(1, foreignMessageLite { c = 1 })
+ assertThat(mapInt32ForeignMessage).isEqualTo(mapOf(1 to foreignMessageLite { c = 1 }))
+ mapInt32ForeignMessage[2] = foreignMessageLite { c = 2 }
+ assertThat(mapInt32ForeignMessage).isEqualTo(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.putAll(
+ mapOf(3 to foreignMessageLite { c = 3 }, 4 to foreignMessageLite { c = 4 })
+ )
+ assertThat(mapInt32ForeignMessage).isEqualTo(
+ mapOf(
+ 1 to foreignMessageLite { c = 1 },
+ 2 to foreignMessageLite { c = 2 },
+ 3 to foreignMessageLite { c = 3 },
+ 4 to foreignMessageLite { c = 4 }
+ )
+ )
+ }
+ }
+
+ @Test
+ fun testMapRemove() {
+ testMapLite {
+ mapInt32Int32.putAll(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.remove(1)
+ assertThat(mapInt32Int32).isEqualTo(mapOf(3 to 4))
+
+ mapStringString.putAll(mapOf("1" to "2", "3" to "4"))
+ mapStringString.remove("1")
+ assertThat(mapStringString).isEqualTo(mapOf("3" to "4"))
+
+ mapInt32Enum.putAll(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.remove(1)
+ assertThat(mapInt32Enum).isEqualTo(mapOf(2 to MapEnumLite.MAP_ENUM_BAR_LITE))
+
+ mapInt32ForeignMessage.putAll(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.remove(1)
+ assertThat(mapInt32ForeignMessage).isEqualTo(mapOf(2 to foreignMessageLite { c = 2 }))
+ }
+ }
+
+ @Test
+ fun testMapClear() {
+ testMapLite {
+ mapInt32Int32.putAll(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.clear()
+ assertThat(mapInt32Int32.isEmpty()).isTrue()
+
+ mapStringString.putAll(mapOf("1" to "2", "3" to "4"))
+ mapStringString.clear()
+ assertThat(mapStringString.isEmpty()).isTrue()
+
+ mapInt32Enum.putAll(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.clear()
+ assertThat(mapInt32Enum.isEmpty()).isTrue()
+
+ mapInt32ForeignMessage.putAll(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.clear()
+ assertThat(mapInt32ForeignMessage.isEmpty()).isTrue()
+ }
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto2 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ += 1
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ by = "foo"
+ }
+ ).isEqualTo(
+ EvilNamesProto2.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .addClass_(1)
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setBy("foo")
+ .build()
+ )
+
+ assertThat(interface_ {}).isEqualTo(Interface.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+}
diff --git a/java/kotlin/generate-sources-build.xml b/java/kotlin/generate-sources-build.xml
new file mode 100644
index 0000000..4e7be23
--- /dev/null
+++ b/java/kotlin/generate-sources-build.xml
@@ -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>
diff --git a/java/kotlin/generate-test-sources-build.xml b/java/kotlin/generate-test-sources-build.xml
new file mode 100644
index 0000000..dca1a05
--- /dev/null
+++ b/java/kotlin/generate-test-sources-build.xml
@@ -0,0 +1,34 @@
+<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="--experimental_allow_proto3_optional"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/map_proto2_unittest.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest.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_proto3.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/example_extensible_message.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_proto3.proto"/>
+ </exec>
+ <exec executable="${protoc}">
+ <arg value="--kotlin_out=${generated.testsources.dir}"/>
+ <arg value="--proto_path=${protobuf.source.dir}"/>
+ <arg value="--proto_path=${test.proto.dir}"/>
+ <arg value="--experimental_allow_proto3_optional"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/map_proto2_unittest.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+ <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
+ <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_proto3.proto"/>
+ </exec>
+
+</project>
diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml
new file mode 100644
index 0000000..8de8aca
--- /dev/null
+++ b/java/kotlin/pom.xml
@@ -0,0 +1,251 @@
+<?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.15.6</version>
+ </parent>
+
+ <artifactId>protobuf-kotlin</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>
+
+ <properties>
+ <kotlin.version>1.4.31</kotlin.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib</artifactId>
+ <version>${kotlin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-test</artifactId>
+ <version>${kotlin.version}</version>
+ <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>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-source-files</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.sources.dir}/com/google/protobuf</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../core/src/main/java/com/google/protobuf</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-test-source-files</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.testsources.dir}/com/google/protobuf</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../core/src/test/java/com/google/protobuf</directory>
+ <includes>
+ <include>TestUtil.java</include>
+ <include>TestUtilLite.java</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- 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>
+ <plugin>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-maven-plugin</artifactId>
+ <version>${kotlin.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>compile</id>
+ <goals> <goal>compile</goal> </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${generated.sources.dir}</sourceDir>
+ <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
+ </sourceDirs>
+ </configuration>
+ </execution>
+ <execution>
+ <id>test-compile</id>
+ <goals> <goal>test-compile</goal> </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
+ <sourceDir>${generated.testsources.dir}</sourceDir>
+ </sourceDirs>
+ </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>
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/DslList.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/DslList.kt
new file mode 100644
index 0000000..54a64af
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/DslList.kt
@@ -0,0 +1,27 @@
+package com.google.protobuf.kotlin
+
+/**
+ * A simple wrapper around a [List] with an extra generic parameter that can be used to disambiguate
+ * extension methods.
+ *
+ * <p>This class is used by Kotlin protocol buffer extensions, and its constructor is public only
+ * because generated message code is in a different compilation unit. Others should not use this
+ * class directly in any way.
+ */
+@Suppress("unused") // the unused type parameter
+class DslList<E, P : DslProxy> @OnlyForUseByGeneratedProtoCode constructor(
+ private val delegate: List<E>
+) : List<E> by delegate {
+ override fun iterator(): Iterator<E> = UnmodifiableIterator(delegate.iterator())
+
+ override fun listIterator(): ListIterator<E> = UnmodifiableListIterator(delegate.listIterator())
+
+ override fun listIterator(index: Int): ListIterator<E> =
+ UnmodifiableListIterator(delegate.listIterator(index))
+
+ override fun equals(other: Any?): Boolean = delegate == other
+
+ override fun hashCode(): Int = delegate.hashCode()
+
+ override fun toString(): String = delegate.toString()
+}
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/DslMap.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/DslMap.kt
new file mode 100644
index 0000000..9949fb4
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/DslMap.kt
@@ -0,0 +1,30 @@
+package com.google.protobuf.kotlin
+
+/**
+ * A simple wrapper around a [Map] with an extra generic parameter that can be used to disambiguate
+ * extension methods.
+ *
+ * <p>This class is used by Kotlin protocol buffer extensions, and its constructor is public only
+ * because generated message code is in a different compilation unit. Others should not use this
+ * class directly in any way.
+ */
+@Suppress("unused") // the unused type parameter
+class DslMap<K, V, P : DslProxy> @OnlyForUseByGeneratedProtoCode constructor(
+ private val delegate: Map<K, V>
+) : Map<K, V> by delegate {
+ // We allocate the wrappers on calls to get, not with lazy {...}, because lazy allocates
+ // a few objects up front, and any kind of query operation on this object should be rare.
+
+ override val entries: Set<Map.Entry<K, V>>
+ get() = UnmodifiableMapEntries(delegate.entries)
+ override val keys: Set<K>
+ get() = UnmodifiableSet(delegate.keys)
+ override val values: Collection<V>
+ get() = UnmodifiableCollection(delegate.values)
+
+ override fun equals(other: Any?): Boolean = delegate == other
+
+ override fun hashCode(): Int = delegate.hashCode()
+
+ override fun toString(): String = delegate.toString()
+}
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/DslProxy.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/DslProxy.kt
new file mode 100644
index 0000000..7d14e95
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/DslProxy.kt
@@ -0,0 +1,12 @@
+package com.google.protobuf.kotlin
+
+/**
+ * A type meaningful only for its existence, never intended to be instantiated. For example,
+ * a `DslList<Int, FooProxy>` can be given different extension methods than a
+ * `DslList<Int, BarProxy>`.
+ */
+abstract class DslProxy @OnlyForUseByGeneratedProtoCode protected constructor() {
+ init {
+ throw UnsupportedOperationException("A DslProxy should never be instantiated")
+ }
+}
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt
new file mode 100644
index 0000000..d1f04a8
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt
@@ -0,0 +1,26 @@
+package com.google.protobuf.kotlin
+
+import com.google.protobuf.ExtensionLite
+import com.google.protobuf.GeneratedMessageV3
+
+/** Sets the current value of the proto extension in this builder.*/
+operator fun <
+ M : GeneratedMessageV3.ExtendableMessage<M>,
+ B : GeneratedMessageV3.ExtendableBuilder<M, B>,
+ T
+ > B.set(extension: ExtensionLite<M, T>, value: T) {
+ setExtension(extension, value)
+}
+
+/** Gets the current value of the proto extension. */
+operator fun <
+ M : GeneratedMessageV3.ExtendableMessage<M>,
+ MorBT : GeneratedMessageV3.ExtendableMessageOrBuilder<M>,
+ T
+ > MorBT.get(extension: ExtensionLite<M, T>): T = getExtension(extension)
+
+/** Returns true if the specified extension is set on this builder. */
+operator fun <
+ M : GeneratedMessageV3.ExtendableMessage<M>,
+ MorBT : GeneratedMessageV3.ExtendableMessageOrBuilder<M>
+ > MorBT.contains(extension: ExtensionLite<M, *>): Boolean = hasExtension(extension)
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt
new file mode 100644
index 0000000..8bd8ed3
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt
@@ -0,0 +1,28 @@
+package com.google.protobuf.kotlin
+
+import com.google.protobuf.ExtensionLite
+import com.google.protobuf.GeneratedMessageLite
+
+/** Gets the value of the proto extension. */
+operator fun <
+ M : GeneratedMessageLite.ExtendableMessage<M, *>,
+ MOrBT : GeneratedMessageLite.ExtendableMessageOrBuilder<M, *>,
+ T
+ > MOrBT.get(extension: ExtensionLite<M, T>): T = getExtension(extension)
+
+/** Sets the current value of the proto extension in this builder. */
+operator fun <
+ M : GeneratedMessageLite.ExtendableMessage<M, B>,
+ B : GeneratedMessageLite.ExtendableBuilder<M, B>,
+ T
+ > B.set(extension: ExtensionLite<M, T>, value: T) {
+ setExtension(extension, value)
+}
+
+/** Returns true if the specified extension is set. */
+operator fun <
+ M : GeneratedMessageLite.ExtendableMessage<M, *>,
+ MorBT : GeneratedMessageLite.ExtendableMessageOrBuilder<M, *>
+ > MorBT.contains(
+ extension: ExtensionLite<M, *>
+): Boolean = hasExtension(extension)
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ExtensionList.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtensionList.kt
new file mode 100644
index 0000000..03764e1
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/ExtensionList.kt
@@ -0,0 +1,27 @@
+package com.google.protobuf.kotlin
+
+import com.google.protobuf.ExtensionLite
+import com.google.protobuf.MessageLite
+
+/**
+ * Implementation for ExtensionList and ExtensionListLite. Like [DslList], represents an
+ * unmodifiable view of a repeated proto field -- in this case, an extension field -- but
+ * supports querying the extension.
+ */
+class ExtensionList<E, M : MessageLite> @OnlyForUseByGeneratedProtoCode constructor(
+ val extension: ExtensionLite<M, List<E>>,
+ @JvmField private val delegate: List<E>
+) : List<E> by delegate {
+ override fun iterator(): Iterator<E> = UnmodifiableIterator(delegate.iterator())
+
+ override fun listIterator(): ListIterator<E> = UnmodifiableListIterator(delegate.listIterator())
+
+ override fun listIterator(index: Int): ListIterator<E> =
+ UnmodifiableListIterator(delegate.listIterator(index))
+
+ override fun equals(other: Any?): Boolean = delegate == other
+
+ override fun hashCode(): Int = delegate.hashCode()
+
+ override fun toString(): String = delegate.toString()
+}
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt
new file mode 100644
index 0000000..368912e
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt
@@ -0,0 +1,18 @@
+package com.google.protobuf.kotlin
+
+/**
+ * Opt-in annotation to make it difficult to accidentally use APIs only intended for use by proto
+ * generated code. See https://kotlinlang.org/docs/reference/opt-in-requirements.html for details
+ * on how this API works.
+ */
+@RequiresOptIn(
+ message =
+ """
+ This API is only intended for use by generated protobuf code, the code generator, and their own
+ tests. If this does not describe your code, you should not be using this API.
+ """,
+ level = RequiresOptIn.Level.ERROR
+)
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.ANNOTATION_CLASS)
+annotation class OnlyForUseByGeneratedProtoCode
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt
new file mode 100644
index 0000000..c51ba35
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt
@@ -0,0 +1,10 @@
+package com.google.protobuf.kotlin
+
+/**
+ * Indicates an API that is part of a DSL to generate protocol buffer messages.
+ */
+@DslMarker
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.BINARY)
+@OnlyForUseByGeneratedProtoCode
+annotation class ProtoDslMarker
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt b/java/kotlin/src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt
new file mode 100644
index 0000000..6af93e1
--- /dev/null
+++ b/java/kotlin/src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt
@@ -0,0 +1,39 @@
+package com.google.protobuf.kotlin
+
+/** Wraps an [Iterator] and makes it unmodifiable even from Java. */
+internal class UnmodifiableIterator<E>(delegate: Iterator<E>) : Iterator<E> by delegate
+
+/** Wraps a [ListIterator] and makes it unmodifiable even from Java. */
+internal class UnmodifiableListIterator<E>(
+ delegate: ListIterator<E>
+) : ListIterator<E> by delegate
+
+/** Wraps a [Collection] and makes it unmodifiable even from Java. */
+internal open class UnmodifiableCollection<E>(
+ private val delegate: Collection<E>
+) : Collection<E> by delegate {
+ override fun iterator(): Iterator<E> = UnmodifiableIterator(delegate.iterator())
+}
+
+/** Wraps a [Set] and makes it unmodifiable even from Java. */
+internal class UnmodifiableSet<E>(
+ delegate: Collection<E>
+) : UnmodifiableCollection<E>(delegate), Set<E>
+
+/** Wraps a [Map.Entry] and makes it unmodifiable even from Java. */
+internal class UnmodifiableMapEntry<K, V>(delegate: Map.Entry<K, V>) : Map.Entry<K, V> by delegate
+
+/** Wraps a [Set] of map entries and makes it unmodifiable even from Java. */
+internal class UnmodifiableMapEntries<K, V>(
+ private val delegate: Set<Map.Entry<K, V>>
+) : UnmodifiableCollection<Map.Entry<K, V>>(delegate), Set<Map.Entry<K, V>> {
+
+ // Is this overkill? Probably.
+
+ override fun iterator(): Iterator<Map.Entry<K, V>> {
+ val itr = delegate.iterator()
+ return object : Iterator<Map.Entry<K, V>> by itr {
+ override fun next(): Map.Entry<K, V> = UnmodifiableMapEntry(itr.next())
+ }
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/DslListTest.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/DslListTest.kt
new file mode 100644
index 0000000..e5e6017
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/DslListTest.kt
@@ -0,0 +1,98 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Tests for [DslList]. */
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class DslListTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesList() {
+ assertThat(DslList<Int, DummyProxy>(listOf(1, 2, 3))).containsExactly(1, 2, 3).inOrder()
+ }
+
+ @Test
+ fun reflectsChangesInList() {
+ val mutableList = mutableListOf(1, 2, 3)
+ val dslList = DslList<Int, DummyProxy>(mutableList)
+ mutableList.add(4)
+ assertThat(dslList).containsExactly(1, 2, 3, 4).inOrder()
+ }
+
+ @Test
+ fun dslListIsNotMutable() {
+ val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
+ assertThat(dslList is MutableList<*>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslListIsNotEvenSecretlyMutable() {
+ val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
+ val dslListAsJavaUtil = dslList as java.util.List<Int>
+ assertFailsWith<UnsupportedOperationException> {
+ dslListAsJavaUtil.add(4)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_IteratorIsNotEvenSecretlyMutable() {
+ val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
+ val iterator = dslList.iterator() as java.util.Iterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_ListIteratorIsNotEvenSecretlyMutable() {
+ val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
+ val iterator = dslList.listIterator() as java.util.ListIterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_ListIteratorIndexIsNotEvenSecretlyMutable() {
+ val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
+ val iterator = dslList.listIterator(1) as java.util.ListIterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(DslList<Int, DummyProxy>(listOf(1, 2)).toString()).isEqualTo("[1, 2]")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(DslList<Int, DummyProxy>(listOf(1, 2)), listOf(1, 2))
+ .addEqualityGroup(DslList<Int, DummyProxy>(listOf(2, 2)), listOf(2, 2))
+ .addEqualityGroup(
+ DslList<Int, DummyProxy>(emptyList()),
+ DslList<String, DummyProxy>(emptyList()),
+ emptyList<Int>()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/DslMapTest.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/DslMapTest.kt
new file mode 100644
index 0000000..470e42e
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/DslMapTest.kt
@@ -0,0 +1,164 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class DslMapTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesMap() {
+ assertThat(DslMap<Int, Int, DummyProxy>(mapOf(1 to -1, 2 to -2)))
+ .containsExactly(1, -1, 2, -2)
+ }
+
+ @Test
+ fun reflectsChangesInMap() {
+ val mutableMap = mutableMapOf(1 to -1, 2 to -2)
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMap)
+ mutableMap[3] = -3
+ assertThat(dslMap).containsExactly(1, -1, 2, -2, 3, -3).inOrder()
+ }
+
+ @Test
+ fun dslMapIsNotMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ assertThat(dslMap is MutableMap<*, *>).isFalse()
+ }
+
+ @Test
+ fun dslMapKeysAreNotMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ assertThat(dslMap.keys is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapValuesAreNotMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ assertThat(dslMap.values is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapEntriesAreNotMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ assertThat(dslMap.entries is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapEntryObjectsAreNotMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ assertThat(dslMap.entries.single() is MutableMap.MutableEntry<*, *>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapAsJavaUtilMap = dslMap as java.util.Map<Int, Int>
+ assertFailsWith<UnsupportedOperationException> {
+ dslMapAsJavaUtilMap.put(2, -2)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapKeysAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapKeysAsJavaUtilSet = dslMap.keys as java.util.Set<Int>
+ assertFailsWith<UnsupportedOperationException> {
+ dslMapKeysAsJavaUtilSet.remove(1)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapKeysIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapKeysAsJavaUtilSet = dslMap.keys as java.util.Set<Int>
+ val itr = dslMapKeysAsJavaUtilSet.iterator()
+ itr.next()
+ assertFailsWith<UnsupportedOperationException> {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapValuesAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapValuesAsJavaUtilCollection = dslMap.values as java.util.Collection<Int>
+ assertFailsWith<UnsupportedOperationException> {
+ dslMapValuesAsJavaUtilCollection.remove(1)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapValuesIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapValuesAsJavaUtilCollection = dslMap.values as java.util.Collection<Int>
+ val itr = dslMapValuesAsJavaUtilCollection.iterator()
+ itr.next()
+ assertFailsWith<UnsupportedOperationException> {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntriesAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapEntriesAsJavaUtilSet = dslMap.entries as java.util.Set<Map.Entry<Int, Int>>
+ val entry = dslMap.entries.single()
+ assertFailsWith<UnsupportedOperationException> {
+ dslMapEntriesAsJavaUtilSet.remove(entry)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntriesIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapEntriesAsJavaUtilSet = dslMap.entries as java.util.Set<Map.Entry<Int, Int>>
+ val itr = dslMapEntriesAsJavaUtilSet.iterator()
+ itr.next()
+ assertFailsWith<UnsupportedOperationException> {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntryObjectsAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
+ val dslMapEntryAsJavaUtilMapEntry = dslMap.entries.single() as java.util.Map.Entry<Int, Int>
+ assertFailsWith<UnsupportedOperationException> {
+ dslMapEntryAsJavaUtilMapEntry.value = 2
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(DslMap<Int, Int, DummyProxy>(mapOf(1 to 2, 2 to 3)).toString())
+ .isEqualTo("{1=2, 2=3}")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(DslMap<Int, Int, DummyProxy>(mapOf(1 to 2, 2 to 3)), mapOf(1 to 2, 2 to 3))
+ .addEqualityGroup(DslMap<Int, Int, DummyProxy>(mapOf(1 to 3, 2 to 3)), mapOf(1 to 3, 2 to 3))
+ .addEqualityGroup(
+ DslMap<Int, Int, DummyProxy>(emptyMap()),
+ DslMap<String, String, DummyProxy>(emptyMap()),
+ emptyMap<Int, Int>()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt
new file mode 100644
index 0000000..c8816eb
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt
@@ -0,0 +1,60 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import example_extensible_message.ExampleExtensibleMessage
+import example_extensible_message.ExampleExtensibleMessageOuterClass as TestProto
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtendableMessageExtensionsTest {
+ @Test
+ fun setOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ builder[TestProto.int32Extension] = 5
+ assertThat(builder.build().getExtension(TestProto.int32Extension)).isEqualTo(5)
+ }
+
+ @Test
+ fun getOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(builder[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun getOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(message[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun containsPositiveOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(TestProto.int32Extension in message).isTrue()
+ }
+
+ @Test
+ fun containsPositiveOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(TestProto.int32Extension in builder).isTrue()
+ }
+
+ @Test
+ fun containsNegativeOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder().build()
+ assertThat(TestProto.int32Extension in message).isFalse()
+ }
+
+ @Test
+ fun containsNegativeOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ assertThat(TestProto.int32Extension in builder).isFalse()
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/ExtensionListTest.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/ExtensionListTest.kt
new file mode 100644
index 0000000..e805e1e
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/ExtensionListTest.kt
@@ -0,0 +1,125 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import example_extensible_message.ExampleExtensibleMessage
+import example_extensible_message.ExampleExtensibleMessageOuterClass as TestProto
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Tests for [DslList]. */
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class ExtensionListTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesList() {
+ assertThat(
+ ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, listOf(1, 2, 3)
+ )
+ ).containsExactly(1, 2, 3).inOrder()
+ }
+
+ @Test
+ fun reflectsChangesInList() {
+ val mutableList = mutableListOf(1, 2, 3)
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableList
+ )
+ mutableList.add(4)
+ assertThat(extensionList).containsExactly(1, 2, 3, 4).inOrder()
+ }
+
+ @Test
+ fun extensionListIsNotMutable() {
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ assertThat(extensionList is MutableList<*>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionListIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val extensionListAsJavaUtil = extensionList as java.util.List<Int>
+ assertFailsWith<UnsupportedOperationException> {
+ extensionListAsJavaUtil.add(4)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_IteratorIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.iterator() as java.util.Iterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_ListIteratorIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.listIterator() as java.util.ListIterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_ListIteratorIndexIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList<Int, ExampleExtensibleMessage>(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.listIterator(1) as java.util.ListIterator<Int>
+ iterator.next()
+
+ assertFailsWith<UnsupportedOperationException> {
+ iterator.remove()
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(
+ ExtensionList<Int, ExampleExtensibleMessage>(TestProto.repeatedExtension, listOf(1, 2))
+ .toString()
+ ).isEqualTo("[1, 2]")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(
+ ExtensionList<Int, ExampleExtensibleMessage>(TestProto.repeatedExtension, listOf(1, 2)),
+ ExtensionList<Int, ExampleExtensibleMessage>(TestProto.differentExtension, listOf(1, 2)),
+ listOf(1, 2)
+ )
+ .addEqualityGroup(
+ ExtensionList<Int, ExampleExtensibleMessage>(TestProto.repeatedExtension, listOf(2, 2)),
+ listOf(2, 2)
+ )
+ .addEqualityGroup(
+ ExtensionList<Int, ExampleExtensibleMessage>(TestProto.repeatedExtension, emptyList()),
+ emptyList<Int>()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
new file mode 100644
index 0000000..72b9792
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
@@ -0,0 +1,891 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.TestUtil
+import com.google.protobuf.TestUtil.toBytes
+import evil_names_proto2.EvilNamesProto2OuterClass.EvilNamesProto2
+import evil_names_proto2.EvilNamesProto2OuterClass.HardKeywordsAllTypes
+import evil_names_proto2.EvilNamesProto2OuterClass.Interface
+import evil_names_proto2.HardKeywordsAllTypesKt
+import evil_names_proto2.evilNamesProto2
+import evil_names_proto2.hardKeywordsAllTypes
+import evil_names_proto2.interface_
+import com.google.protobuf.test.UnittestImport.ImportEnum
+import com.google.protobuf.test.UnittestImport.ImportMessage
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage
+import protobuf_unittest.MapProto2Unittest.Proto2MapEnum
+import protobuf_unittest.MapProto2Unittest.TestEnumMap
+import protobuf_unittest.MapProto2Unittest.TestIntIntMap
+import protobuf_unittest.MapProto2Unittest.TestMaps
+import protobuf_unittest.TestAllTypesKt
+import protobuf_unittest.TestAllTypesKt.nestedMessage
+import protobuf_unittest.UnittestProto
+import protobuf_unittest.UnittestProto.ForeignEnum
+import protobuf_unittest.UnittestProto.TestAllTypes
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedEnum
+import protobuf_unittest.UnittestProto.TestEmptyMessage
+import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions
+import protobuf_unittest.copy
+import protobuf_unittest.foreignMessage
+import protobuf_unittest.optionalGroupExtension
+import protobuf_unittest.repeatedGroupExtension
+import protobuf_unittest.testAllExtensions
+import protobuf_unittest.testAllTypes
+import protobuf_unittest.testEmptyMessage
+import protobuf_unittest.testEmptyMessageWithExtensions
+import protobuf_unittest.testEnumMap
+import protobuf_unittest.testIntIntMap
+import protobuf_unittest.testMaps
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto2Test {
+ @Test
+ fun testSetters() {
+ assertThat(
+ testAllTypes {
+ optionalInt32 = 101
+ optionalInt64 = 102
+ optionalUint32 = 103
+ optionalUint64 = 104
+ optionalSint32 = 105
+ optionalSint64 = 106
+ optionalFixed32 = 107
+ optionalFixed64 = 108
+ optionalSfixed32 = 109
+ optionalSfixed64 = 110
+ optionalFloat = 111.0f
+ optionalDouble = 112.0
+ optionalBool = true
+ optionalString = "115"
+ optionalBytes = toBytes("116")
+ optionalGroup =
+ TestAllTypesKt.optionalGroup { a = 117 }
+ optionalNestedMessage = nestedMessage { bb = 118 }
+ optionalForeignMessage = foreignMessage { c = 119 }
+ optionalImportMessage =
+ ImportMessage.newBuilder().setD(120).build()
+ optionalPublicImportMessage =
+ PublicImportMessage.newBuilder().setE(126).build()
+ optionalLazyMessage = nestedMessage { bb = 127 }
+ optionalNestedEnum = NestedEnum.BAZ
+ optionalForeignEnum = ForeignEnum.FOREIGN_BAZ
+ optionalImportEnum = ImportEnum.IMPORT_BAZ
+ optionalStringPiece = "124"
+ optionalCord = "125"
+ repeatedInt32.add(201)
+ repeatedInt64.add(202)
+ repeatedUint32.add(203)
+ repeatedUint64.add(204)
+ repeatedSint32.add(205)
+ repeatedSint64.add(206)
+ repeatedFixed32.add(207)
+ repeatedFixed64.add(208)
+ repeatedSfixed32.add(209)
+ repeatedSfixed64.add(210)
+ repeatedFloat.add(211f)
+ repeatedDouble.add(212.0)
+ repeatedBool.add(true)
+ repeatedString.add("215")
+ repeatedBytes.add(toBytes("216"))
+ repeatedGroup.add(TestAllTypesKt.repeatedGroup { a = 217 })
+ repeatedNestedMessage.add(nestedMessage { bb = 218 })
+ repeatedForeignMessage.add(foreignMessage { c = 219 })
+ repeatedImportMessage.add(
+ ImportMessage.newBuilder().setD(220).build()
+ )
+ repeatedLazyMessage.add(nestedMessage { bb = 227 })
+ repeatedNestedEnum.add(NestedEnum.BAR)
+ repeatedForeignEnum.add(ForeignEnum.FOREIGN_BAR)
+ repeatedImportEnum.add(ImportEnum.IMPORT_BAR)
+ repeatedStringPiece.add("224")
+ repeatedCord.add("225")
+ repeatedInt32 += 301
+ repeatedInt64 += 302
+ repeatedUint32 += 303
+ repeatedUint64 += 304
+ repeatedSint32 += 305
+ repeatedSint64 += 306
+ repeatedFixed32 += 307
+ repeatedFixed64 += 308
+ repeatedSfixed32 += 309
+ repeatedSfixed64 += 310
+ repeatedFloat += 311f
+ repeatedDouble += 312.0
+ repeatedBool += false
+ repeatedString += "315"
+ repeatedBytes += toBytes("316")
+ repeatedGroup += TestAllTypesKt.repeatedGroup { a = 317 }
+ repeatedNestedMessage += nestedMessage { bb = 318 }
+ repeatedForeignMessage += foreignMessage { c = 319 }
+ repeatedImportMessage +=
+ ImportMessage.newBuilder().setD(320).build()
+ repeatedLazyMessage +=
+ TestAllTypesKt.nestedMessage { bb = 327 }
+ repeatedNestedEnum += NestedEnum.BAZ
+ repeatedForeignEnum += ForeignEnum.FOREIGN_BAZ
+ repeatedImportEnum += ImportEnum.IMPORT_BAZ
+ repeatedStringPiece += "324"
+ repeatedCord += "325"
+ defaultInt32 = 401
+ defaultInt64 = 402
+ defaultUint32 = 403
+ defaultUint64 = 404
+ defaultSint32 = 405
+ defaultSint64 = 406
+ defaultFixed32 = 407
+ defaultFixed64 = 408
+ defaultSfixed32 = 409
+ defaultSfixed64 = 410
+ defaultFloat = 411f
+ defaultDouble = 412.0
+ defaultBool = false
+ defaultString = "415"
+ defaultBytes = toBytes("416")
+ defaultNestedEnum = NestedEnum.FOO
+ defaultForeignEnum = ForeignEnum.FOREIGN_FOO
+ defaultImportEnum = ImportEnum.IMPORT_FOO
+ defaultStringPiece = "424"
+ defaultCord = "425"
+ oneofUint32 = 601
+ oneofNestedMessage =
+ TestAllTypesKt.nestedMessage { bb = 602 }
+ oneofString = "603"
+ oneofBytes = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtil.getAllSetBuilder().build()
+ )
+ }
+
+ @Test
+ fun testGetters() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ assertThat(optionalGroup).isEqualTo(TestAllTypesKt.optionalGroup { a = 117 })
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ defaultInt32 = 401
+ assertThat(defaultInt32).isEqualTo(401)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testDefaultGetters() {
+ testAllTypes {
+ assertThat(defaultInt32).isEqualTo(41)
+ assertThat(defaultString).isEqualTo("hello")
+ assertThat(defaultNestedEnum).isEqualTo(NestedEnum.BAR)
+ assertThat(defaultStringPiece).isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypes {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedGroup.addAll(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 }
+ )
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 }
+ )
+ )
+ repeatedGroup +=
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 },
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ )
+ repeatedGroup[0] = TestAllTypesKt.repeatedGroup { a = 5 }
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 5 },
+ TestAllTypesKt.repeatedGroup { a = 2 },
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ )
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testHazzers() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(hasOptionalInt32()).isTrue()
+ assertThat(hasOptionalString()).isFalse()
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ assertThat(hasOptionalGroup()).isTrue()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(hasOptionalNestedEnum()).isTrue()
+ assertThat(hasDefaultInt32()).isFalse()
+ oneofUint32 = 601
+ assertThat(hasOneofUint32()).isTrue()
+ }
+
+ testAllTypes {
+ assertThat(hasOptionalInt32()).isFalse()
+ optionalString = "115"
+ assertThat(hasOptionalString()).isTrue()
+ assertThat(hasOptionalGroup()).isFalse()
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(hasOptionalNestedMessage()).isTrue()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+ defaultInt32 = 401
+ assertThat(hasDefaultInt32()).isTrue()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testClears() {
+ testAllTypes {
+ optionalInt32 = 101
+ clearOptionalInt32()
+ assertThat(hasOptionalInt32()).isFalse()
+
+ optionalString = "115"
+ clearOptionalString()
+ assertThat(hasOptionalString()).isFalse()
+
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ clearOptionalGroup()
+ assertThat(hasOptionalGroup()).isFalse()
+
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+
+ defaultInt32 = 401
+ clearDefaultInt32()
+ assertThat(hasDefaultInt32()).isFalse()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypes {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypes {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(hasOneofUint32()).isFalse()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testExtensionsSet() {
+ assertThat(
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ this[UnittestProto.optionalInt64Extension] = 102L
+ this[UnittestProto.optionalUint32Extension] = 103
+ this[UnittestProto.optionalUint64Extension] = 104L
+ this[UnittestProto.optionalSint32Extension] = 105
+ this[UnittestProto.optionalSint64Extension] = 106L
+ this[UnittestProto.optionalFixed32Extension] = 107
+ this[UnittestProto.optionalFixed64Extension] = 108L
+ this[UnittestProto.optionalSfixed32Extension] = 109
+ this[UnittestProto.optionalSfixed64Extension] = 110L
+ this[UnittestProto.optionalFloatExtension] = 111F
+ this[UnittestProto.optionalDoubleExtension] = 112.0
+ this[UnittestProto.optionalBoolExtension] = true
+ this[UnittestProto.optionalStringExtension] = "115"
+ this[UnittestProto.optionalBytesExtension] = toBytes("116")
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ this[UnittestProto.optionalForeignMessageExtension] = foreignMessage { c = 119 }
+ this[UnittestProto.optionalImportMessageExtension] =
+ ImportMessage.newBuilder().setD(120).build()
+ this[UnittestProto.optionalPublicImportMessageExtension] =
+ PublicImportMessage.newBuilder().setE(126).build()
+ this[UnittestProto.optionalLazyMessageExtension] = TestAllTypesKt.nestedMessage { bb = 127 }
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ this[UnittestProto.optionalForeignEnumExtension] = ForeignEnum.FOREIGN_BAZ
+ this[UnittestProto.optionalImportEnumExtension] = ImportEnum.IMPORT_BAZ
+ this[UnittestProto.optionalStringPieceExtension] = "124"
+ this[UnittestProto.optionalCordExtension] = "125"
+ this[UnittestProto.repeatedInt32Extension].add(201)
+ this[UnittestProto.repeatedInt64Extension].add(202L)
+ this[UnittestProto.repeatedUint32Extension].add(203)
+ this[UnittestProto.repeatedUint64Extension].add(204L)
+ this[UnittestProto.repeatedSint32Extension].add(205)
+ this[UnittestProto.repeatedSint64Extension].add(206L)
+ this[UnittestProto.repeatedFixed32Extension].add(207)
+ this[UnittestProto.repeatedFixed64Extension].add(208L)
+ this[UnittestProto.repeatedSfixed32Extension].add(209)
+ this[UnittestProto.repeatedSfixed64Extension].add(210L)
+ this[UnittestProto.repeatedFloatExtension].add(211F)
+ this[UnittestProto.repeatedDoubleExtension].add(212.0)
+ this[UnittestProto.repeatedBoolExtension].add(true)
+ this[UnittestProto.repeatedStringExtension].add("215")
+ this[UnittestProto.repeatedBytesExtension].add(toBytes("216"))
+ this[UnittestProto.repeatedGroupExtension].add(repeatedGroupExtension { a = 217 })
+ this[UnittestProto.repeatedNestedMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 218 })
+ this[UnittestProto.repeatedForeignMessageExtension].add(foreignMessage { c = 219 })
+ this[UnittestProto.repeatedImportMessageExtension]
+ .add(ImportMessage.newBuilder().setD(220).build())
+ this[UnittestProto.repeatedLazyMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 227 })
+ this[UnittestProto.repeatedNestedEnumExtension].add(NestedEnum.BAR)
+ this[UnittestProto.repeatedForeignEnumExtension].add(ForeignEnum.FOREIGN_BAR)
+ this[UnittestProto.repeatedImportEnumExtension].add(ImportEnum.IMPORT_BAR)
+ this[UnittestProto.repeatedStringPieceExtension].add("224")
+ this[UnittestProto.repeatedCordExtension].add("225")
+ this[UnittestProto.repeatedInt32Extension].add(301)
+ this[UnittestProto.repeatedInt64Extension].add(302L)
+ this[UnittestProto.repeatedUint32Extension].add(303)
+ this[UnittestProto.repeatedUint64Extension].add(304L)
+ this[UnittestProto.repeatedSint32Extension].add(305)
+ this[UnittestProto.repeatedSint64Extension].add(306L)
+ this[UnittestProto.repeatedFixed32Extension].add(307)
+ this[UnittestProto.repeatedFixed64Extension].add(308L)
+ this[UnittestProto.repeatedSfixed32Extension].add(309)
+ this[UnittestProto.repeatedSfixed64Extension].add(310L)
+ this[UnittestProto.repeatedFloatExtension].add(311F)
+ this[UnittestProto.repeatedDoubleExtension].add(312.0)
+ this[UnittestProto.repeatedBoolExtension].add(false)
+ this[UnittestProto.repeatedStringExtension].add("315")
+ this[UnittestProto.repeatedBytesExtension].add(toBytes("316"))
+ this[UnittestProto.repeatedGroupExtension].add(repeatedGroupExtension { a = 317 })
+ this[UnittestProto.repeatedNestedMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 318 })
+ this[UnittestProto.repeatedForeignMessageExtension].add(foreignMessage { c = 319 })
+ this[UnittestProto.repeatedImportMessageExtension]
+ .add(ImportMessage.newBuilder().setD(320).build())
+ this[UnittestProto.repeatedLazyMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 327 })
+ this[UnittestProto.repeatedNestedEnumExtension].add(NestedEnum.BAZ)
+ this[UnittestProto.repeatedForeignEnumExtension].add(ForeignEnum.FOREIGN_BAZ)
+ this[UnittestProto.repeatedImportEnumExtension].add(ImportEnum.IMPORT_BAZ)
+ this[UnittestProto.repeatedStringPieceExtension].add("324")
+ this[UnittestProto.repeatedCordExtension].add("325")
+ this[UnittestProto.defaultInt32Extension] = 401
+ this[UnittestProto.defaultInt64Extension] = 402L
+ this[UnittestProto.defaultUint32Extension] = 403
+ this[UnittestProto.defaultUint64Extension] = 404L
+ this[UnittestProto.defaultSint32Extension] = 405
+ this[UnittestProto.defaultSint64Extension] = 406L
+ this[UnittestProto.defaultFixed32Extension] = 407
+ this[UnittestProto.defaultFixed64Extension] = 408L
+ this[UnittestProto.defaultSfixed32Extension] = 409
+ this[UnittestProto.defaultSfixed64Extension] = 410L
+ this[UnittestProto.defaultFloatExtension] = 411F
+ this[UnittestProto.defaultDoubleExtension] = 412.0
+ this[UnittestProto.defaultBoolExtension] = false
+ this[UnittestProto.defaultStringExtension] = "415"
+ this[UnittestProto.defaultBytesExtension] = toBytes("416")
+ this[UnittestProto.defaultNestedEnumExtension] = NestedEnum.FOO
+ this[UnittestProto.defaultForeignEnumExtension] = ForeignEnum.FOREIGN_FOO
+ this[UnittestProto.defaultImportEnumExtension] = ImportEnum.IMPORT_FOO
+ this[UnittestProto.defaultStringPieceExtension] = "424"
+ this[UnittestProto.defaultCordExtension] = "425"
+ this[UnittestProto.oneofUint32Extension] = 601
+ this[UnittestProto.oneofNestedMessageExtension] = TestAllTypesKt.nestedMessage { bb = 602 }
+ this[UnittestProto.oneofStringExtension] = "603"
+ this[UnittestProto.oneofBytesExtension] = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtil.getAllExtensionsSet()
+ )
+ }
+
+ @Test
+ fun testExtensionGetters() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ assertThat(this[UnittestProto.optionalInt32Extension]).isEqualTo(101)
+ this[UnittestProto.optionalStringExtension] = "115"
+ assertThat(this[UnittestProto.optionalStringExtension]).isEqualTo("115")
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ assertThat(this[UnittestProto.optionalGroupExtension])
+ .isEqualTo(optionalGroupExtension { a = 117 })
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(this[UnittestProto.optionalNestedMessageExtension])
+ .isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ assertThat(this[UnittestProto.optionalNestedEnumExtension]).isEqualTo(NestedEnum.BAZ)
+ this[UnittestProto.defaultInt32Extension] = 401
+ assertThat(this[UnittestProto.defaultInt32Extension]).isEqualTo(401)
+ this[UnittestProto.oneofUint32Extension] = 601
+ assertThat(this[UnittestProto.oneofUint32Extension]).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testExtensionContains() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isTrue()
+ assertThat(contains(UnittestProto.optionalStringExtension)).isFalse()
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isFalse()
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isTrue()
+ assertThat(contains(UnittestProto.defaultInt32Extension)).isFalse()
+ this[UnittestProto.oneofUint32Extension] = 601
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isTrue()
+ }
+
+ testAllExtensions {
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isFalse()
+ this[UnittestProto.optionalStringExtension] = "115"
+ assertThat(contains(UnittestProto.optionalStringExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isFalse()
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isFalse()
+ this[UnittestProto.defaultInt32Extension] = 401
+ assertThat(contains(UnittestProto.defaultInt32Extension)).isTrue()
+ assertThat(contains(UnittestProto.oneofUint32Extension)).isFalse()
+ }
+ }
+
+ @Test
+ fun testExtensionClears() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ clear(UnittestProto.optionalInt32Extension)
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isFalse()
+
+ this[UnittestProto.optionalStringExtension] = "115"
+ clear(UnittestProto.optionalStringExtension)
+ assertThat(contains(UnittestProto.optionalStringExtension)).isFalse()
+
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ clear(UnittestProto.optionalGroupExtension)
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isFalse()
+
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ clear(UnittestProto.optionalNestedMessageExtension)
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isFalse()
+
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ clear(UnittestProto.optionalNestedEnumExtension)
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isFalse()
+
+ this[UnittestProto.defaultInt32Extension] = 401
+ clear(UnittestProto.defaultInt32Extension)
+ assertThat(contains(UnittestProto.oneofUint32Extension)).isFalse()
+ }
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessage {}
+ ).isEqualTo(
+ TestEmptyMessage.newBuilder().build()
+ )
+
+ assertThat(
+ testEmptyMessageWithExtensions {}
+ ).isEqualTo(
+ TestEmptyMessageWithExtensions.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testMapSetters() {
+ val intMap = testIntIntMap { m[1] = 2 }
+ assertThat(intMap).isEqualTo(
+ TestIntIntMap.newBuilder().putM(1, 2).build()
+ )
+
+ assertThat(
+ testMaps {
+ mInt32[1] = intMap
+ mInt64[1L] = intMap
+ mUint32[1] = intMap
+ mUint64[1L] = intMap
+ mSint32[1] = intMap
+ mSint64[1L] = intMap
+ mFixed32[1] = intMap
+ mFixed64[1L] = intMap
+ mSfixed32[1] = intMap
+ mSfixed64[1] = intMap
+ mBool[true] = intMap
+ mString["1"] = intMap
+ }
+ ).isEqualTo(
+ TestMaps.newBuilder()
+ .putMInt32(1, intMap)
+ .putMInt64(1L, intMap)
+ .putMUint32(1, intMap)
+ .putMUint64(1L, intMap)
+ .putMSint32(1, intMap)
+ .putMSint64(1L, intMap)
+ .putMFixed32(1, intMap)
+ .putMFixed64(1L, intMap)
+ .putMSfixed32(1, intMap)
+ .putMSfixed64(1L, intMap)
+ .putMBool(true, intMap)
+ .putMString("1", intMap)
+ .build()
+ )
+
+ assertThat(
+ testEnumMap {
+ knownMapField[1] = Proto2MapEnum.PROTO2_MAP_ENUM_FOO
+ }
+ ).isEqualTo(
+ TestEnumMap.newBuilder()
+ .putKnownMapField(1, Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ .build()
+ )
+ }
+
+ @Test
+ fun testMapGettersAndSetters() {
+ val intMap =
+ testIntIntMap {
+ m.put(1, 2)
+ assertThat(m).isEqualTo(mapOf(1 to 2))
+ m[3] = 4
+ assertThat(m).isEqualTo(mapOf(1 to 2, 3 to 4))
+ m.putAll(mapOf(5 to 6, 7 to 8))
+ assertThat(m).isEqualTo(mapOf(1 to 2, 3 to 4, 5 to 6, 7 to 8))
+ }
+
+ testMaps {
+ mInt32.put(1, intMap)
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap))
+ mInt32[2] = intMap
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap, 2 to intMap))
+ mInt32.putAll(mapOf(3 to intMap, 4 to intMap))
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap, 2 to intMap, 3 to intMap, 4 to intMap))
+
+ mString.put("1", intMap)
+ assertThat(mString).isEqualTo(mapOf("1" to intMap))
+ mString["2"] = intMap
+ assertThat(mString).isEqualTo(mapOf("1" to intMap, "2" to intMap))
+ mString.putAll(mapOf("3" to intMap, "4" to intMap))
+ assertThat(mString).isEqualTo(
+ mapOf("1" to intMap, "2" to intMap, "3" to intMap, "4" to intMap)
+ )
+ }
+
+ testEnumMap {
+ knownMapField.put(1, Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ assertThat(knownMapField).isEqualTo(mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO))
+ knownMapField[2] = Proto2MapEnum.PROTO2_MAP_ENUM_BAR
+ assertThat(knownMapField).isEqualTo(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.putAll(
+ mapOf(3 to Proto2MapEnum.PROTO2_MAP_ENUM_BAZ, 4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ )
+ assertThat(knownMapField).isEqualTo(
+ mapOf(
+ 1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO,
+ 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR,
+ 3 to Proto2MapEnum.PROTO2_MAP_ENUM_BAZ,
+ 4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO
+ )
+ )
+ }
+ }
+
+ @Test
+ fun testMapRemove() {
+ val intMap =
+ testIntIntMap {
+ m.putAll(mapOf(1 to 2, 3 to 4))
+ m.remove(1)
+ assertThat(m).isEqualTo(mapOf(3 to 4))
+ }
+
+ testMaps {
+ mInt32.putAll(mapOf(1 to intMap, 2 to intMap))
+ mInt32.remove(1)
+ assertThat(mInt32).isEqualTo(mapOf(2 to intMap))
+
+ mString.putAll(mapOf("1" to intMap, "2" to intMap))
+ mString.remove("1")
+ assertThat(mString).isEqualTo(mapOf("2" to intMap))
+ }
+
+ testEnumMap {
+ knownMapField.putAll(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.remove(1)
+ assertThat(knownMapField).isEqualTo(mapOf(2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR))
+ }
+ }
+
+ @Test
+ fun testMapClear() {
+ val intMap =
+ testIntIntMap {
+ m.putAll(mapOf(1 to 2, 3 to 4))
+ m.clear()
+ assertThat(m.isEmpty()).isTrue()
+ }
+
+ testMaps {
+ mInt32.putAll(mapOf(1 to intMap, 2 to intMap))
+ mInt32.clear()
+ assertThat(mInt32.isEmpty()).isTrue()
+
+ mString.putAll(mapOf("1" to intMap, "2" to intMap))
+ mString.clear()
+ assertThat(mString.isEmpty()).isTrue()
+ }
+
+ testEnumMap {
+ knownMapField.putAll(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.clear()
+ assertThat(knownMapField.isEmpty()).isTrue()
+ }
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto2 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ += 1
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ by = "foo"
+ }
+ ).isEqualTo(
+ EvilNamesProto2.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .addClass_(1)
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setBy("foo")
+ .build()
+ )
+
+ assertThat(interface_ {}).isEqualTo(Interface.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+}
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
new file mode 100644
index 0000000..b3fd336
--- /dev/null
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
@@ -0,0 +1,340 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import evil_names_proto3.EvilNamesProto3OuterClass.EvilNamesProto3
+import evil_names_proto3.EvilNamesProto3OuterClass.HardKeywordsAllTypes
+import evil_names_proto3.EvilNamesProto3OuterClass.Class
+import evil_names_proto3.HardKeywordsAllTypesKt
+import evil_names_proto3.class_
+import evil_names_proto3.evilNamesProto3
+import evil_names_proto3.hardKeywordsAllTypes
+import multiple_files_proto3.MultipleFilesMessageA
+import multiple_files_proto3.MultipleFilesMessageB
+import multiple_files_proto3.multipleFilesMessageA
+import multiple_files_proto3.multipleFilesMessageB
+import proto3_unittest.UnittestProto3
+import proto3_unittest.TestAllTypesKt
+import proto3_unittest.TestAllTypesKt.nestedMessage
+import proto3_unittest.UnittestProto3.TestAllTypes
+import proto3_unittest.UnittestProto3.TestAllTypes.NestedEnum
+import proto3_unittest.UnittestProto3.TestEmptyMessage
+import proto3_unittest.copy
+import proto3_unittest.testAllTypes
+import proto3_unittest.testEmptyMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto3Test {
+ @Test
+ fun testGettersAndSetters() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypes {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testClears() {
+ assertThat(
+ testAllTypes {
+ optionalInt32 = 101
+ clearOptionalInt32()
+
+ optionalString = "115"
+ clearOptionalString()
+
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ }
+ ).isEqualTo(
+ TestAllTypes.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypes {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypes {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessage {}
+ ).isEqualTo(
+ TestEmptyMessage.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto3 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ = "foo"
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ value = "foo"
+ index = 1L
+ values += "foo"
+ newValues += "foo"
+ builder = true
+ k[1] = 1
+ v["foo"] = "foo"
+ key["foo"] = 1
+ map[1] = "foo"
+ pairs["foo"] = 1
+ LeadingUnderscore = "foo"
+ option = 1
+ }
+ ).isEqualTo(
+ EvilNamesProto3.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .setClass_("foo")
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setValue("foo")
+ .setIndex(1L)
+ .addValues("foo")
+ .addNewValues("foo")
+ .setBuilder(true)
+ .putK(1, 1)
+ .putV("foo", "foo")
+ .putKey("foo", 1)
+ .putMap(1, "foo")
+ .putPairs("foo", 1)
+ .setLeadingUnderscore("foo")
+ .setOption(1)
+ .build()
+ )
+
+ assertThat(class_ {}).isEqualTo(Class.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+
+ @Test
+ fun testMultipleFiles() {
+ assertThat(
+ multipleFilesMessageA {}
+ ).isEqualTo(
+ MultipleFilesMessageA.newBuilder().build()
+ )
+
+ assertThat(
+ multipleFilesMessageB {}
+ ).isEqualTo(
+ MultipleFilesMessageB.newBuilder().build()
+ )
+ }
+}
diff --git a/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto2.proto b/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto2.proto
new file mode 100644
index 0000000..70d813a
--- /dev/null
+++ b/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto2.proto
@@ -0,0 +1,62 @@
+syntax = "proto2";
+
+package evil_names_proto2;
+
+option java_package = "evil_names_proto2";
+
+message EvilNamesProto2 {
+ optional bool initialized = 1;
+ optional bool has_foo = 2;
+ optional string Bar = 3;
+ optional bool is_initialized = 4;
+
+ oneof camelCase {
+ string fooBar = 5;
+ }
+
+ repeated string ALL_CAPS = 7;
+ map<int32, bool> ALL_CAPS_MAP = 8;
+
+ optional bool has_underbar_preceding_numeric_1foo = 9;
+ optional bool has_underbar_preceding_numeric_42bar = 13;
+ optional bool has_underbar_preceding_numeric_123foo42bar_baz = 14;
+
+ extensions 100 to max;
+
+ repeated string extension = 12;
+ repeated int32 class = 15;
+ optional double int = 16;
+ optional bool long = 17;
+ optional int64 boolean = 18;
+ optional string sealed = 19;
+ optional float interface = 20;
+ optional int32 in = 21;
+ optional string object = 22;
+ optional string cached_size = 23;
+ optional bool serialized_size = 24;
+ optional string by = 25;
+}
+
+message HardKeywordsAllTypes {
+ message NestedMessage {
+ optional int32 while = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ }
+
+ optional int32 as = 1;
+ optional string in = 2;
+ optional NestedEnum break = 3;
+ map<int32, int32> continue = 4;
+ optional NestedMessage do = 5;
+
+ repeated int32 else = 6;
+ repeated string for = 7;
+ repeated NestedEnum fun = 8;
+ repeated NestedMessage if = 9;
+}
+
+message Interface {}
diff --git a/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto3.proto b/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto3.proto
new file mode 100644
index 0000000..1b40e4d
--- /dev/null
+++ b/java/kotlin/src/test/proto/com/google/protobuf/evil_names_proto3.proto
@@ -0,0 +1,76 @@
+syntax = "proto3";
+
+package evil_names_proto3;
+
+option java_package = "evil_names_proto3";
+
+message EvilNamesProto3 {
+ bool initialized = 1;
+ bool has_foo = 2;
+ string Bar = 3;
+ bool is_initialized = 4;
+
+ oneof camelCase {
+ string fooBar = 5;
+ }
+
+ repeated string ALL_CAPS = 7;
+ map<int32, bool> ALL_CAPS_MAP = 8;
+
+ bool has_underbar_preceding_numeric_1foo = 9;
+ bool has_underbar_preceding_numeric_42bar = 10;
+ bool has_underbar_preceding_numeric_123foo42bar_baz = 11;
+
+ repeated string extension = 12;
+
+ string class = 13;
+ double int = 14;
+ bool long = 15;
+ int64 boolean = 16;
+ string sealed = 17;
+ float interface = 18;
+ int32 in = 19;
+ string object = 20;
+ string cached_size = 21;
+ bool serialized_size = 22;
+ string value = 23;
+ int64 index = 24;
+ repeated string values = 25;
+ repeated string new_values = 26;
+ bool builder = 27;
+ map<int32, int32> k = 28;
+ map<string, string> v = 29;
+ map<string, int32> key = 30;
+ map<int32, string> map = 31;
+ map<string, int32> pairs = 32;
+
+ string _leading_underscore = 33;
+ oneof _leading_underscore_oneof {
+ int32 option = 34;
+ }
+}
+
+message HardKeywordsAllTypes {
+ message NestedMessage {
+ optional int32 while = 1;
+ }
+
+ enum NestedEnum {
+ ZERO = 0;
+ FOO = 1;
+ BAR = 2;
+ }
+
+ optional int32 as = 1;
+ optional string in = 2;
+ optional NestedEnum break = 3;
+ map<int32, int32> continue = 4;
+ optional NestedMessage do = 5;
+
+ repeated int32 else = 6;
+ repeated string for = 7;
+ repeated NestedEnum fun = 8;
+ repeated NestedMessage if = 9;
+}
+
+message Class {}
diff --git a/java/kotlin/src/test/proto/com/google/protobuf/example_extensible_message.proto b/java/kotlin/src/test/proto/com/google/protobuf/example_extensible_message.proto
new file mode 100644
index 0000000..14f18db
--- /dev/null
+++ b/java/kotlin/src/test/proto/com/google/protobuf/example_extensible_message.proto
@@ -0,0 +1,16 @@
+syntax = "proto2";
+
+package example_extensible_message;
+
+option java_package = "example_extensible_message";
+option java_multiple_files = true;
+
+message ExampleExtensibleMessage {
+ extensions 10 to 20;
+}
+
+extend ExampleExtensibleMessage {
+ repeated int32 repeated_extension = 10;
+ repeated int32 different_extension = 11;
+ optional int32 int32_extension = 12;
+}
diff --git a/java/kotlin/src/test/proto/com/google/protobuf/multiple_files_proto3.proto b/java/kotlin/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
new file mode 100644
index 0000000..82211cc
--- /dev/null
+++ b/java/kotlin/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package multiple_files_proto3;
+
+option java_package = "multiple_files_proto3";
+option java_multiple_files = true;
+
+enum NestedEnum { FOO = 0; }
+
+message MultipleFilesMessageA {}
+
+message MultipleFilesMessageB {}
diff --git a/src/Makefile.am b/src/Makefile.am
index e67f37f..ccae399 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -150,6 +150,7 @@
google/protobuf/compiler/csharp/csharp_generator.h \
google/protobuf/compiler/csharp/csharp_names.h \
google/protobuf/compiler/java/java_generator.h \
+ google/protobuf/compiler/java/java_kotlin_generator.h \
google/protobuf/compiler/java/java_names.h \
google/protobuf/compiler/js/js_generator.h \
google/protobuf/compiler/js/well_known_types_embed.h \
@@ -374,6 +375,7 @@
google/protobuf/compiler/java/java_generator_factory.h \
google/protobuf/compiler/java/java_helpers.cc \
google/protobuf/compiler/java/java_helpers.h \
+ google/protobuf/compiler/java/java_kotlin_generator.cc \
google/protobuf/compiler/java/java_map_field.cc \
google/protobuf/compiler/java/java_map_field.h \
google/protobuf/compiler/java/java_map_field_lite.cc \
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 9a0799e..e68eb77 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -63,6 +63,7 @@
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->enum_type());
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
@@ -76,6 +77,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
// Use deprecated valueOf() method to be compatible with old generated code
// for v2.5.0/v2.6.1.
@@ -270,6 +276,34 @@
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for enums
@@ -1037,6 +1071,98 @@
"}\n");
}
+void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
std::string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 95c7db5..a8cd033 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -80,6 +80,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -138,6 +139,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index 8403f95..dd442fe 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -70,6 +70,7 @@
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->enum_type());
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
@@ -83,6 +84,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -275,6 +281,34 @@
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableEnumFieldLiteGenerator::GenerateInitializationCode(
io::Printer* printer) const {
if (!IsDefaultValueJavaDefault(descriptor_)) {
@@ -774,6 +808,98 @@
printer->Print(variables_, "$name$_ = emptyIntList();\n");
}
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
std::string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h
index fbc1127..99249fe 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h
@@ -73,6 +73,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -118,6 +119,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index 2f775a6..db5a332 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -258,6 +258,11 @@
// empty string.
(*variables)["{"] = "";
(*variables)["}"] = "";
+ (*variables)["kt_name"] =
+ IsForbiddenKotlin(info->name) ? info->name + "_" : info->name;
+ (*variables)["kt_capitalized_name"] = IsForbiddenKotlin(info->name)
+ ? info->capitalized_name + "_"
+ : info->capitalized_name;
}
void SetCommonOneofVariables(const FieldDescriptor* descriptor,
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index df6c38d..a7c995c 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -84,6 +84,7 @@
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateFieldBuilderInitializationCode(
io::Printer* printer) const = 0;
+ virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
virtual void GenerateHashCode(io::Printer* printer) const = 0;
@@ -106,6 +107,7 @@
virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
virtual void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const = 0;
+ virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
virtual std::string GetBoxedType() const = 0;
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 5cdb00d..e8801a1 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -675,6 +675,53 @@
}
}
+std::string FileGenerator::GetKotlinClassname() {
+ return name_resolver_->GetFileClassName(file_, immutable_api_, true);
+}
+
+void FileGenerator::GenerateKotlinSiblings(
+ const std::string& package_dir, GeneratorContext* context,
+ std::vector<std::string>* file_list,
+ std::vector<std::string>* annotation_list) {
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ const Descriptor* descriptor = file_->message_type(i);
+ MessageGenerator* generator = message_generators_[i].get();
+ auto open_file = [context](const string& filename) {
+ return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename));
+ };
+ std::string filename = package_dir + descriptor->name() + "Kt.kt";
+ file_list->push_back(filename);
+ std::string info_full_path = filename + ".pb.meta";
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ auto output = open_file(filename);
+ io::Printer printer(
+ output.get(), '$',
+ options_.annotate_code ? &annotation_collector : nullptr);
+
+ printer.Print(
+ "//Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", descriptor->file()->name());
+ if (!java_package_.empty()) {
+ printer.Print(
+ "package $package$;\n"
+ "\n",
+ "package", java_package_);
+ }
+
+ generator->GenerateKotlinMembers(&printer);
+ generator->GenerateTopLevelKotlinMembers(&printer);
+
+ if (options_.annotate_code) {
+ auto info_output = open_file(info_full_path);
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ annotation_list->push_back(info_full_path);
+ }
+ }
+}
bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor,
bool immutable_api) {
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 9f1f719..71ee3e8 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -78,6 +78,11 @@
void Generate(io::Printer* printer);
+ std::string GetKotlinClassname();
+ void GenerateKotlinSiblings(const std::string& package_dir,
+ GeneratorContext* generator_context,
+ std::vector<std::string>* file_list,
+ std::vector<std::string>* annotation_list);
// If we aren't putting everything into one file, this will write all the
// files other than the outer file (i.e. one for each message, enum, and
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index e32b6e3..1020043 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -91,6 +91,17 @@
"transient", "try", "void", "volatile", "while",
});
+// Names that should be avoided as field names in Kotlin.
+// All Kotlin hard keywords are in this list.
+const std::unordered_set<std::string>* kKotlinForbiddenNames =
+ new std::unordered_set<std::string>({
+ "as", "as?", "break", "class", "continue", "do", "else",
+ "false", "for", "fun", "if", "in", "!in", "interface",
+ "is", "!is", "null", "object", "package", "return", "super",
+ "this", "throw", "true", "try", "typealias", "typeof", "val",
+ "var", "when", "while",
+ });
+
bool IsForbidden(const std::string& field_name) {
for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) {
if (field_name == kForbiddenWordList[i]) {
@@ -156,6 +167,38 @@
StrCat(enum_verifier_string, terminating_string).c_str());
}
+std::string ToCamelCase(const std::string& input, bool lower_first) {
+ bool capitalize_next = !lower_first;
+ std::string result;
+ result.reserve(input.size());
+
+ for (char i : input) {
+ if (i == '_') {
+ capitalize_next = true;
+ } else if (capitalize_next) {
+ result.push_back(ToUpperCh(i));
+ capitalize_next = false;
+ } else {
+ result.push_back(i);
+ }
+ }
+
+ // Lower-case the first letter.
+ if (lower_first && !result.empty()) {
+ result[0] = ToLowerCh(result[0]);
+ }
+
+ return result;
+}
+
+char ToUpperCh(char ch) {
+ return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
+}
+
+char ToLowerCh(char ch) {
+ return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
+}
+
std::string UnderscoresToCamelCase(const std::string& input,
bool cap_next_letter) {
GOOGLE_CHECK(!input.empty());
@@ -217,6 +260,10 @@
return name;
}
+bool IsForbiddenKotlin(const std::string& field_name) {
+ return kKotlinForbiddenNames->find(field_name) !=
+ kKotlinForbiddenNames->end();
+}
std::string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
@@ -423,6 +470,35 @@
return BoxedPrimitiveTypeName(GetJavaType(descriptor));
}
+const char* KotlinTypeName(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT:
+ return "kotlin.Int";
+ case JAVATYPE_LONG:
+ return "kotlin.Long";
+ case JAVATYPE_FLOAT:
+ return "kotlin.Float";
+ case JAVATYPE_DOUBLE:
+ return "kotlin.Double";
+ case JAVATYPE_BOOLEAN:
+ return "kotlin.Boolean";
+ case JAVATYPE_STRING:
+ return "kotlin.String";
+ case JAVATYPE_BYTES:
+ return "com.google.protobuf.ByteString";
+ case JAVATYPE_ENUM:
+ return NULL;
+ case JAVATYPE_MESSAGE:
+ return NULL;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
std::string GetOneofStoredType(const FieldDescriptor* field) {
const JavaType javaType = GetJavaType(field);
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 5ede13c..13dd903 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -53,6 +53,7 @@
extern const char kThickSeparator[];
extern const char kThinSeparator[];
+bool IsForbiddenKotlin(const std::string& field_name);
// If annotation_file is non-empty, prints a javax.annotation.Generated
// annotation to the given Printer. annotation_file will be referenced in the
@@ -75,6 +76,13 @@
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
// first letter.
+std::string ToCamelCase(const std::string& input, bool lower_first);
+
+char ToUpperCh(char ch);
+char ToLowerCh(char ch);
+
+// Converts a name to camel-case. If cap_first_letter is true, capitalize the
+// first letter.
std::string UnderscoresToCamelCase(const std::string& name,
bool cap_first_letter);
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
@@ -216,6 +224,9 @@
// types.
const char* BoxedPrimitiveTypeName(JavaType type);
+// Kotlin source does not distinguish between primitives and non-primitives,
+// but does use Kotlin-specific qualified types for them.
+const char* KotlinTypeName(JavaType type);
// Get the name of the java enum constant representing this type. E.g.,
// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full
diff --git a/src/google/protobuf/compiler/java/java_kotlin_generator.cc b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
new file mode 100644
index 0000000..5a5d198
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
@@ -0,0 +1,130 @@
+#include <google/protobuf/compiler/java/java_kotlin_generator.h>
+
+#include <memory>
+
+#include <google/protobuf/compiler/java/java_file.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_options.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+KotlinGenerator::KotlinGenerator() {}
+KotlinGenerator::~KotlinGenerator() {}
+
+uint64_t KotlinGenerator::GetSupportedFeatures() const {
+ return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+bool KotlinGenerator::Generate(const FileDescriptor* file,
+ const std::string& parameter,
+ GeneratorContext* context,
+ std::string* error) const {
+ // -----------------------------------------------------------------
+ // parse generator options
+
+ std::vector<std::pair<std::string, std::string> > options;
+ ParseGeneratorParameter(parameter, &options);
+ Options file_options;
+
+ for (auto& option : options) {
+ if (option.first == "output_list_file") {
+ file_options.output_list_file = option.second;
+ } else if (option.first == "immutable") {
+ file_options.generate_immutable_code = true;
+ } else if (option.first == "mutable") {
+ *error = "Mutable not supported by Kotlin generator";
+ return false;
+ } else if (option.first == "shared") {
+ file_options.generate_shared_code = true;
+ } else if (option.first == "lite") {
+ file_options.enforce_lite = true;
+ } else if (option.first == "annotate_code") {
+ file_options.annotate_code = true;
+ } else if (option.first == "annotation_list_file") {
+ file_options.annotation_list_file = option.second;
+ } else {
+ *error = "Unknown generator option: " + option.first;
+ return false;
+ }
+ }
+
+ // By default we generate immutable code and shared code for immutable API.
+ if (!file_options.generate_immutable_code &&
+ !file_options.generate_shared_code) {
+ file_options.generate_immutable_code = true;
+ file_options.generate_shared_code = true;
+ }
+
+ std::vector<std::string> all_files;
+ std::vector<std::string> all_annotations;
+
+ std::unique_ptr<FileGenerator> file_generator(new FileGenerator(file, file_options, /* immutable_api = */ true));
+
+ if (!file_generator->Validate(error)) {
+ return false;
+ }
+
+ auto open_file = [context](const string& filename) {
+ return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename));
+ };
+ std::string package_dir = JavaPackageToDir(file_generator->java_package());
+ std::string kotlin_filename = package_dir;
+ kotlin_filename += file_generator->GetKotlinClassname();
+ kotlin_filename += ".kt";
+ all_files.push_back(kotlin_filename);
+ std::string info_full_path = kotlin_filename + ".pb.meta";
+ if (file_options.annotate_code) {
+ all_annotations.push_back(info_full_path);
+ }
+
+ // Generate main kotlin file.
+ auto output = open_file(kotlin_filename);
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+ &annotations);
+ io::Printer printer(
+ output.get(), '$',
+ file_options.annotate_code ? &annotation_collector : nullptr);
+
+ file_generator->GenerateKotlinSiblings(package_dir, context, &all_files,
+ &all_annotations);
+
+ if (file_options.annotate_code) {
+ auto info_output = open_file(info_full_path);
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ }
+
+ // Generate output list if requested.
+ if (!file_options.output_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .kt files being generated.
+ auto srclist_raw_output = open_file(file_options.output_list_file);
+ io::Printer srclist_printer(srclist_raw_output.get(), '$');
+ for (auto& all_file : all_files) {
+ srclist_printer.Print("$filename$\n", "filename", all_file);
+ }
+ }
+
+ if (!file_options.annotation_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .kt files being generated.
+ auto annotation_list_raw_output =
+ open_file(file_options.annotation_list_file);
+ io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+ for (auto& all_annotation : all_annotations) {
+ annotation_list_printer.Print("$filename$\n", "filename", all_annotation);
+ }
+ }
+
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} //namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/java/java_kotlin_generator.h b/src/google/protobuf/compiler/java/java_kotlin_generator.h
new file mode 100644
index 0000000..db15353
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_kotlin_generator.h
@@ -0,0 +1,40 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H_
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// CodeGenerator implementation which generates Kotlin code. If you create your
+// own protocol compiler binary and you want it to support Kotlin output, you
+// can do so by registering an instance of this CodeGenerator with the
+// CommandLineInterface in your main() function.
+class PROTOC_EXPORT KotlinGenerator : public CodeGenerator {
+ public:
+ KotlinGenerator();
+ ~KotlinGenerator() override;
+
+ // implements CodeGenerator ----------------------------------------
+ bool Generate(const FileDescriptor* file, const std::string& parameter,
+ GeneratorContext* context, std::string* error) const override;
+
+ uint64_t GetSupportedFeatures() const override;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(KotlinGenerator);
+};
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_KOTLIN_GENERATOR_H_
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 5db199d..a4ec2ff 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -69,6 +69,17 @@
}
}
+std::string KotlinTypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return KotlinTypeName(GetJavaType(field));
+ }
+}
+
std::string WireType(const FieldDescriptor* field) {
return "com.google.protobuf.WireFormat.FieldType." +
std::string(FieldTypeName(field->type()));
@@ -91,6 +102,8 @@
(*variables)["key_type"] = TypeName(key, name_resolver, false);
std::string boxed_key_type = TypeName(key, name_resolver, true);
(*variables)["boxed_key_type"] = boxed_key_type;
+ (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+ (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
// Used for calling the serialization function.
(*variables)["short_key_type"] =
boxed_key_type.substr(boxed_key_type.rfind('.') + 1);
@@ -136,6 +149,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
// For repeated fields, one bit is used for whether the array is immutable
@@ -651,6 +669,87 @@
}
}
+void ImmutableMapFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @JvmName(\"get$kt_capitalized_name$Map\")\n"
+ " get() = com.google.protobuf.kotlin.DslMap(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+ " )\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@JvmName(\"put$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"set$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " put(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"remove$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .remove(key: $kt_key_type$) {\n"
+ " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+ "{\n"
+ " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ " }\n");
+}
+
void ImmutableMapFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// Nothing to initialize.
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index 2ff1f76..63b2577 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -62,6 +62,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index 8db281d..023b4fc 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -71,6 +71,17 @@
}
}
+std::string KotlinTypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return KotlinTypeName(GetJavaType(field));
+ }
+}
+
std::string WireType(const FieldDescriptor* field) {
return "com.google.protobuf.WireFormat.FieldType." +
std::string(FieldTypeName(field->type()));
@@ -92,6 +103,8 @@
(*variables)["key_type"] = TypeName(key, name_resolver, false);
(*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+ (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+ (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
(*variables)["key_wire_type"] = WireType(key);
(*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
// We use `x.getClass()` as a null check because it generates less bytecode
@@ -137,6 +150,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["default_entry"] =
(*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry";
@@ -794,6 +812,87 @@
}
}
+void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @JvmName(\"get$kt_capitalized_name$Map\")\n"
+ " get() = com.google.protobuf.kotlin.DslMap(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+ " )\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@JvmName(\"put$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"set$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " put(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"remove$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .remove(key: $kt_key_type$) {\n"
+ " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+ "{\n"
+ " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ " }\n");
+}
+
void ImmutableMapFieldLiteGenerator::GenerateInitializationCode(
io::Printer* printer) const {
// Nothing to initialize.
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h
index 37aec06..62c162d 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.h
@@ -55,6 +55,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index f2df25f..5425ad9 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -1358,6 +1358,243 @@
}
}
+void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+ printer->Print(
+ "class Dsl private constructor(\n"
+ " @kotlin.jvm.JvmField private val _builder: $message$.Builder\n"
+ ") {\n"
+ " companion object {\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _create(builder: $message$.Builder): Dsl = "
+ "Dsl(builder)\n"
+ " }\n"
+ "\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _build(): $message$ = _builder.build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateKotlinDslMembers(printer);
+ }
+
+ for (auto oneof : oneofs_) {
+ printer->Print(
+ "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+ " @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+ " get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+ "fun clear$oneof_capitalized_name$() {\n"
+ " _builder.clear$oneof_capitalized_name$()\n"
+ "}\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+ name_resolver_->GetClassName(descriptor_, true));
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ GenerateKotlinExtensions(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ "
+ "=\n"
+ " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+ "}._build()\n",
+ "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+ "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+ printer->Indent();
+ GenerateKotlinDsl(printer);
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+ .GenerateKotlinMembers(printer);
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+ "}._build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+ name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+ .GenerateTopLevelKotlinMembers(printer);
+ }
+}
+
+void ImmutableMessageGenerator::GenerateKotlinExtensions(
+ io::Printer* printer) const {
+ std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+ printer->Print(
+ "@Suppress(\"UNCHECKED_CAST\")\n"
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun <T> get(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+ " return if (extension.isRepeated) {\n"
+ " get(extension as com.google.protobuf.ExtensionLite<$message$, "
+ "List<*>>) as T\n"
+ " } else {\n"
+ " _builder.getExtension(extension)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+ "operator fun <E> get(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
+ "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
+ " return com.google.protobuf.kotlin.ExtensionList(extension, "
+ "_builder.getExtension(extension))\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun contains(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, *>): "
+ "Boolean {\n"
+ " return _builder.hasExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun clear(extension: com.google.protobuf.ExtensionLite<$message$, *>) "
+ "{\n"
+ " _builder.clearExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.PublishedApi\n"
+ "internal fun <T> setExtension(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>, "
+ "value: T) {\n"
+ " _builder.setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <T : Comparable<T>> set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, "
+ "com.google.protobuf.ByteString>,\n"
+ " value: com.google.protobuf.ByteString\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.add(value: E) {\n"
+ " _builder.addExtension(this.extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.plusAssign"
+ "(value: E) {\n"
+ " add(value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.addAll(values: Iterable<E>) {\n"
+ " for (value in values) {\n"
+ " add(value)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.plusAssign(values: "
+ "Iterable<E>) {\n"
+ " addAll(values)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.set(index: Int, value: "
+ "E) {\n"
+ " _builder.setExtension(this.extension, index, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+ "$message$>.clear() {\n"
+ " clear(extension)\n"
+ "}\n\n",
+ "message", message_name);
+}
+
void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
printer->Print(
"private static String getTypeUrl(\n"
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 87b9df5..50d7180 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -85,6 +85,9 @@
// Generate code to register all contained extensions with an
// ExtensionRegistry.
virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0;
+ virtual void GenerateKotlinDsl(io::Printer* printer) const = 0;
+ virtual void GenerateKotlinMembers(io::Printer* printer) const = 0;
+ virtual void GenerateTopLevelKotlinMembers(io::Printer* printer) const = 0;
protected:
const Descriptor* descriptor_;
@@ -107,6 +110,9 @@
// Returns an estimate of the number of bytes the printed code will compile to
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+ void GenerateKotlinDsl(io::Printer* printer) const override;
+ void GenerateKotlinMembers(io::Printer* printer) const override;
+ void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
private:
void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
@@ -128,6 +134,7 @@
void GenerateEqualsAndHashCode(io::Printer* printer);
void GenerateParser(io::Printer* printer);
void GenerateParsingConstructor(io::Printer* printer);
+ void GenerateKotlinExtensions(io::Printer* printer) const;
void GenerateAnyMethods(io::Printer* printer);
Context* context_;
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index f657c17..a6d5dfe 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -60,6 +60,7 @@
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->message_type());
(*variables)["group_or_message"] =
@@ -69,6 +70,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
(*variables)["ver"] = GeneratedCodeVersionSuffix();
(*variables)["get_parser"] =
@@ -407,6 +413,32 @@
"}\n");
}
+void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+}
+
void ImmutableMessageFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
if (HasHasbit(descriptor_)) {
@@ -1361,6 +1393,98 @@
return name_resolver_->GetImmutableClassName(descriptor_->message_type());
}
+void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 36fa492..08c5e91 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -81,6 +81,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -146,6 +147,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
index 73f1bcf..adb91a3 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -61,6 +61,7 @@
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->message_type());
(*variables)["group_or_message"] =
@@ -70,6 +71,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -277,6 +283,32 @@
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+}
+
void ImmutableMessageFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector<uint16_t>* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
@@ -751,6 +783,98 @@
return name_resolver_->GetImmutableClassName(descriptor_->message_type());
}
+void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
index 8b935e6..af0129c 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -73,6 +73,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -118,6 +119,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index cae9963..74ce6d6 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -724,6 +724,242 @@
}
}
+void ImmutableMessageLiteGenerator::GenerateKotlinDsl(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+ printer->Print(
+ "class Dsl private constructor(\n"
+ " @kotlin.jvm.JvmField private val _builder: $message$.Builder\n"
+ ") {\n"
+ " companion object {\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _create(builder: $message$.Builder): Dsl = "
+ "Dsl(builder)\n"
+ " }\n"
+ "\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _build(): $message$ = _builder.build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateKotlinDslMembers(printer);
+ }
+
+ for (auto oneof : oneofs_) {
+ printer->Print(
+ "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+ " @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+ " get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+ "fun clear$oneof_capitalized_name$() {\n"
+ " _builder.clear$oneof_capitalized_name$()\n"
+ "}\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+ name_resolver_->GetClassName(descriptor_, true));
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ GenerateKotlinExtensions(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+ "}._build()\n",
+ "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+ "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+ printer->Indent();
+ GenerateKotlinDsl(printer);
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateKotlinMembers(printer);
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+ "}._build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+ name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateTopLevelKotlinMembers(printer);
+ }
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinExtensions(
+ io::Printer* printer) const {
+ std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+ printer->Print(
+ "@Suppress(\"UNCHECKED_CAST\")\n"
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun <T> get(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+ " return if (extension.isRepeated) {\n"
+ " get(extension as com.google.protobuf.ExtensionLite<$message$, "
+ "List<*>>) as T\n"
+ " } else {\n"
+ " _builder.getExtension(extension)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+ "operator fun <E> get(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
+ "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
+ " return com.google.protobuf.kotlin.ExtensionList(extension, "
+ "_builder.getExtension(extension))\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun contains(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, *>): "
+ "Boolean {\n"
+ " return _builder.hasExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun clear(extension: com.google.protobuf.ExtensionLite<$message$, *>) "
+ "{\n"
+ " _builder.clearExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.PublishedApi\n"
+ "internal fun <T> setExtension(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>, "
+ "value: T) {\n"
+ " _builder.setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <T : Comparable<T>> set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, "
+ "com.google.protobuf.ByteString>,\n"
+ " value: com.google.protobuf.ByteString\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.add(value: E) {\n"
+ " _builder.addExtension(this.extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.plusAssign"
+ "(value: E) {\n"
+ " add(value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.addAll(values: Iterable<E>) {\n"
+ " for (value in values) {\n"
+ " add(value)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.plusAssign(values: "
+ "Iterable<E>) {\n"
+ " addAll(values)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+ "$message$>.set(index: Int, value: "
+ "E) {\n"
+ " _builder.setExtension(this.extension, index, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+ "$message$>.clear() {\n"
+ " clear(extension)\n"
+ "}\n\n",
+ "message", message_name);
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 5290b1e..4dfa291 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -56,6 +56,9 @@
virtual void GenerateStaticVariables(io::Printer* printer,
int* bytecode_estimate);
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+ void GenerateKotlinDsl(io::Printer* printer) const override;
+ void GenerateKotlinMembers(io::Printer* printer) const override;
+ void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
private:
void GenerateParseFromMethods(io::Printer* printer);
@@ -66,6 +69,7 @@
void GenerateParser(io::Printer* printer);
void GenerateConstructor(io::Printer* printer);
void GenerateDynamicMethodNewBuildMessageInfo(io::Printer* printer);
+ void GenerateKotlinExtensions(io::Printer* printer) const;
Context* context_;
ClassNameResolver* name_resolver_;
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index ed33dae..43c7db5 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -69,6 +69,16 @@
return StripPackageName(descriptor->full_name(), descriptor->file());
}
+std::string ClassNameWithoutPackageKotlin(const Descriptor* descriptor) {
+ std::string result = descriptor->name();
+ const Descriptor* temp = descriptor->containing_type();
+
+ while (temp) {
+ result = temp->name() + "Kt." + result;
+ temp = temp->containing_type();
+ }
+ return result;
+}
// Get the name of an enum's Java class without package name prefix.
std::string ClassNameWithoutPackage(const EnumDescriptor* descriptor,
@@ -316,6 +326,12 @@
descriptor->name();
}
+std::string ClassNameResolver::GetKotlinFactoryName(
+ const Descriptor* descriptor) {
+ std::string name = ToCamelCase(descriptor->name(), /* lower_first = */ true);
+ return IsForbiddenKotlin(name) ? name + "_" : name;
+}
+
std::string ClassNameResolver::GetJavaImmutableClassName(
const Descriptor* descriptor) {
return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true),
@@ -328,6 +344,12 @@
descriptor->file(), true);
}
+std::string ClassNameResolver::GetKotlinExtensionsClassName(
+ const Descriptor* descriptor) {
+ return GetClassFullName(ClassNameWithoutPackageKotlin(descriptor),
+ descriptor->file(), true, true, true);
+}
+
} // namespace java
} // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index 8461df9..9717d92 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -115,6 +115,8 @@
// com.package.OuterClass$OuterMessage$InnerMessage
std::string GetJavaImmutableClassName(const Descriptor* descriptor);
std::string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
+ std::string GetKotlinFactoryName(const Descriptor* descriptor);
+ std::string GetKotlinExtensionsClassName(const Descriptor* descriptor);
private:
// Get the full name of a Java class by prepending the Java package name
// or outer class name.
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 65cc05a..2bc565c 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -68,6 +68,7 @@
(*variables)["type"] = PrimitiveTypeName(javaType);
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+ (*variables)["kt_type"] = KotlinTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE ||
@@ -129,6 +130,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
int fixed_size = FixedSize(GetType(descriptor));
if (fixed_size != -1) {
(*variables)["fixed_size"] = StrCat(fixed_size);
@@ -298,6 +304,33 @@
"}\n");
}
+void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
@@ -793,6 +826,98 @@
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutablePrimitiveFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index db20750..56be916 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -81,6 +81,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -139,6 +140,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 1932e99..cc589f3 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -74,6 +74,7 @@
JavaType javaType = GetJavaType(descriptor);
(*variables)["type"] = PrimitiveTypeName(javaType);
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+ (*variables)["kt_type"] = KotlinTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["capitalized_type"] =
@@ -137,6 +138,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
int fixed_size = FixedSize(GetType(descriptor));
if (fixed_size != -1) {
(*variables)["fixed_size"] = StrCat(fixed_size);
@@ -303,6 +309,33 @@
printer->Annotate("{", "}", descriptor_);
}
+void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
void ImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector<uint16_t>* output) const {
@@ -615,6 +648,98 @@
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector<uint16_t>* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
index 22a2557..b9fcacd 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -73,6 +73,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -119,7 +120,8 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
-
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
+
std::string GetBoxedType() const;
private:
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 2e9a9e7..8d72d95 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -90,6 +90,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
if (HasHasbit(descriptor)) {
@@ -367,6 +372,34 @@
"}\n");
}
+void ImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: kotlin.String\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for primitives
@@ -916,6 +949,107 @@
"}\n");
}
+void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ // property for List<String>
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+ printer->Print(
+ variables_,
+ "val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ // List<String>.add(String)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List<String> += String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List<String>.addAll(Iterable<String>)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List<String> += Iterable<String>
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List<String>[Int] = String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutableStringFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 1c00ae8..6cc9126 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -81,6 +81,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -137,6 +138,7 @@
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index 63702c1..f22fc4b 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -86,6 +86,11 @@
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -304,6 +309,34 @@
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: kotlin.String\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableStringFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector<uint16_t>* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
@@ -704,6 +737,107 @@
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ // property for List<String>
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+ printer->Print(
+ variables_,
+ "val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ // List<String>.add(String)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List<String> += String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: kotlin.String) {\n"
+ " add(value)\n"
+ "}\n");
+
+ // List<String>.addAll(Iterable<String>)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List<String> += Iterable<String>
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n"
+ " addAll(values)\n"
+ "}\n");
+
+ // List<String>[Int] = String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutableStringFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector<uint16_t>* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
index 194a19d..c95256f 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -74,6 +74,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -118,6 +119,7 @@
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 895b47d..7cb7a63 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -30,6 +30,7 @@
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/java/java_generator.h>
+#include <google/protobuf/compiler/java/java_kotlin_generator.h>
#include <google/protobuf/compiler/js/js_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/compiler/python/python_generator.h>
@@ -64,6 +65,10 @@
cli.RegisterGenerator("--java_out", "--java_opt", &java_generator,
"Generate Java source file.");
+ // Proto2 Kotlin
+ java::KotlinGenerator kt_generator;
+ cli.RegisterGenerator("--kotlin_out", "--kotlin_opt", &kt_generator,
+ "Generate Kotlin file.");
// Proto2 Python