Adding kotlin bazel tests
diff --git a/BUILD b/BUILD
index 45a64ab..738034e 100644
--- a/BUILD
+++ b/BUILD
@@ -656,6 +656,8 @@
 TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
 
 GENERIC_RELATIVE_TEST_PROTOS = [
+    "google/protobuf/map_proto2_unittest.proto",
+    "google/protobuf/map_unittest.proto",
     "google/protobuf/unittest.proto",
     "google/protobuf/unittest_arena.proto",
     "google/protobuf/unittest_custom_options.proto",
@@ -1182,7 +1184,7 @@
     name = "generated_protos_proto",
     srcs = [
         "src/google/protobuf/unittest_import_public.proto",
-        "unittest_gen.proto",
+        "unittest_gen_import.proto",
     ],
 )
 
@@ -1190,7 +1192,7 @@
     name = "generated_protos_py",
     srcs = [
         "src/google/protobuf/unittest_import_public.proto",
-        "unittest_gen.proto",
+        "unittest_gen_import.proto",
     ],
     default_runtime = "",
     protoc = ":protoc",
@@ -1320,6 +1322,19 @@
 #     ],
 # )
 
+
+java_proto_library(
+    name = "java_test_protos",
+    deps = [":generic_test_protos"],
+    visibility = ["//visibility:public"],
+)
+
+java_lite_proto_library(
+    name = "java_lite_test_protos",
+    deps = [":generic_test_protos"],
+    visibility = ["//visibility:public"],
+)
+
 java_proto_library(
     name = "test_messages_proto2_java_proto",
     visibility = [
@@ -1413,3 +1428,146 @@
     srcs = glob(["**/*.bzl"]),
     visibility = ["//visibility:public"],
 )
+
+# Kotlin proto rules
+
+genrule(
+    name = "gen_kotlin_unittest_lite",
+    srcs = [
+        "src/google/protobuf/unittest_lite.proto",
+        "src/google/protobuf/unittest_import_lite.proto",
+        "src/google/protobuf/unittest_import_public_lite.proto",
+        "src/google/protobuf/map_lite_unittest.proto",
+    ],
+    outs = [
+        "TestAllTypesLiteKt.kt",
+        "ForeignMessageLiteKt.kt",
+        "TestAllExtensionsLiteKt.kt",
+        "TestEmptyMessageLiteKt.kt",
+        "TestEmptyMessageWithExtensionsLiteKt.kt",
+        "TestMapLiteKt.kt",
+        "OptionalGroup_extension_liteKt.kt",
+        "RepeatedGroup_extension_liteKt.kt",
+    ],
+    visibility = ["//visibility:public"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(locations src/google/protobuf/unittest_lite.proto) && " +
+          "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(locations src/google/protobuf/map_lite_unittest.proto) && " +
+          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
+          "$(location TestAllTypesLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/ForeignMessageLiteKt.kt " +
+          "$(location ForeignMessageLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestAllExtensionsLiteKt.kt " +
+          "$(location TestAllExtensionsLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
+          "$(location TestAllTypesLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestEmptyMessageLiteKt.kt " +
+          "$(location TestEmptyMessageLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestEmptyMessageWithExtensionsLiteKt.kt " +
+          "$(location TestEmptyMessageWithExtensionsLiteKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestMapLiteKt.kt " +
+          "$(location TestMapLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/OptionalGroup_extension_liteKt.kt " +
+          "$(location OptionalGroup_extension_liteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/RepeatedGroup_extension_liteKt.kt " +
+          "$(location RepeatedGroup_extension_liteKt.kt)",
+    tools = [":protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_unittest",
+    srcs = [
+        "src/google/protobuf/unittest.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+        "src/google/protobuf/map_proto2_unittest.proto",
+    ],
+    outs = [
+        "TestAllTypesKt.kt",
+        "ForeignMessageKt.kt",
+        "TestAllExtensionsKt.kt",
+        "TestEmptyMessageKt.kt",
+        "TestEmptyMessageWithExtensionsKt.kt",
+        "TestIntIntMapKt.kt",
+        "TestEnumMapKt.kt",
+        "TestMapsKt.kt",
+        "OptionalGroup_extensionKt.kt",
+        "RepeatedGroup_extensionKt.kt",
+    ],
+    visibility = ["//visibility:public"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest.proto) && " +
+          "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " + 
+          "$(location src/google/protobuf/map_proto2_unittest.proto) && " +
+          "cp $(@D)/protobuf_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/ForeignMessageKt.kt " +
+          "$(location ForeignMessageKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestAllExtensionsKt.kt " +
+          "$(location TestAllExtensionsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEmptyMessageWithExtensionsKt.kt " +
+          "$(location TestEmptyMessageWithExtensionsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestIntIntMapKt.kt " +
+          "$(location TestIntIntMapKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEnumMapKt.kt " +
+          "$(location TestEnumMapKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestMapsKt.kt " +
+          "$(location TestMapsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/OptionalGroup_extensionKt.kt " +
+          "$(location OptionalGroup_extensionKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/RepeatedGroup_extensionKt.kt " +
+          "$(location RepeatedGroup_extensionKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_unittest_lite",
+    srcs = [
+        "src/google/protobuf/unittest_proto3_lite.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+    ],
+    outs = [
+        "TestAllTypesProto3LiteKt.kt",
+        "TestEmptyMessageProto3LiteKt.kt",
+    ],
+    visibility = ["//visibility:public"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest_proto3_lite.proto) && " +
+          "cp $(@D)/proto3_lite_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesProto3LiteKt.kt) && " +
+          "cp $(@D)/proto3_lite_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageProto3LiteKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_unittest",
+    srcs = [
+        "src/google/protobuf/unittest_proto3.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+    ],
+    outs = [
+        "TestAllTypesProto3Kt.kt",
+        "TestEmptyMessageProto3Kt.kt",
+    ],
+    visibility = ["//visibility:public"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest_proto3.proto) && " +
+          "cp $(@D)/proto3_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesProto3Kt.kt) && " +
+          "cp $(@D)/proto3_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
diff --git a/WORKSPACE b/WORKSPACE
index 8104dcc..5778a58 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -59,3 +59,18 @@
 
 load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
 rules_pkg_dependencies()
+
+# For `kt_jvm_library`
+rules_kotlin_version = "v1.5.0-beta-4"
+rules_kotlin_sha = "6cbd4e5768bdfae1598662e40272729ec9ece8b7bded8f0d2c81c8ff96dc139d"
+http_archive(
+    name = "io_bazel_rules_kotlin",
+    urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % rules_kotlin_version],
+    sha256 = rules_kotlin_sha,
+)
+
+load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
+kotlin_repositories()
+
+load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
+kt_register_toolchains()
diff --git a/java/BUILD b/java/BUILD
index e12d472..7a244d8 100644
--- a/java/BUILD
+++ b/java/BUILD
@@ -2,6 +2,8 @@
     name = "tests",
     tests = [
         "//java/core:tests",
+        "//java/kotlin:tests",
+        "//java/kotlin-lite:tests",
         "//java/lite:tests",
         "//java/util:tests",
     ],
@@ -11,6 +13,7 @@
     name = "release",
     srcs = [
         "//java/core:release", # contains lite.
+        "//java/kotlin:release", # contains kotlin lite.
         "//java/util:release",
     ]
-)
\ No newline at end of file
+)
diff --git a/java/core/BUILD b/java/core/BUILD
index aa7ba62..a698fc8 100644
--- a/java/core/BUILD
+++ b/java/core/BUILD
@@ -231,6 +231,7 @@
         "@maven//:com_google_guava_guava",
         "@maven//:junit_junit",
     ],
+    visibility = ["//java:__subpackages__"],
 )
 
 test_suite(
@@ -334,6 +335,7 @@
     ],
     visibility = [
         "//java/lite:__pkg__",
+        "//java/kotlin-lite:__pkg__",
     ],
     deps = [
         ":generic_test_protos_java_proto_lite",
diff --git a/java/kotlin-lite/BUILD b/java/kotlin-lite/BUILD
new file mode 100644
index 0000000..c9dab1d
--- /dev/null
+++ b/java/kotlin-lite/BUILD
@@ -0,0 +1,169 @@
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library", "kt_jvm_test")
+load("@rules_java//java:defs.bzl", "java_lite_proto_library")
+
+java_lite_proto_library(
+    name = "example_extensible_message_java_proto_lite",
+    deps = ["//java/kotlin:example_extensible_message_proto"],
+)
+
+kt_jvm_library(
+    name = "lite_extensions",
+    srcs = ["src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt"],
+    deps = ["//java/lite"],
+)
+
+test_suite(
+    name = "tests",
+    tests = [
+        "test_lite_extensions",
+        "proto2_test_lite",
+        "proto3_test_lite",
+    ],
+)
+
+kt_jvm_test(
+    name = "test_lite_extensions",
+    srcs = ["src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt"],
+    deps = [
+        ":example_extensible_message_java_proto_lite",
+        ":lite_extensions",
+        "//java/lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.ExtendableMessageLiteExtensionsTest",
+)
+
+java_lite_proto_library(
+    name = "evil_names_proto2_java_proto_lite",
+    deps = ["//java/kotlin:evil_names_proto2"],
+)
+
+java_lite_proto_library(
+    name = "evil_names_proto3_java_proto_lite",
+    deps = ["//java/kotlin:evil_names_proto3"],
+)
+
+java_lite_proto_library(
+    name = "multiple_files_proto3_java_proto_lite",
+    deps = ["//java/kotlin:multiple_files_proto3"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_java_multiple_files_lite",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    outs = [
+        "MultipleFilesMessageALiteKt.kt",
+        "MultipleFilesMessageBLiteKt.kt",
+        "MultipleFilesProto3LiteKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
+          "$(location MultipleFilesMessageALiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
+          "$(location MultipleFilesMessageBLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
+          "$(location MultipleFilesProto3LiteKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto2_lite",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    outs = [
+        "EvilNamesProto2LiteKt.kt",
+        "HardKeywordsAllTypesProto2LiteKt.kt",
+        "InterfaceKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
+          "$(location EvilNamesProto2LiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
+          "$(location HardKeywordsAllTypesProto2LiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
+          "$(location InterfaceKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto3_lite",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    outs = [
+        "ClassKt.kt",
+        "EvilNamesProto3Kt.kt",
+        "HardKeywordsAllTypesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
+          "$(location ClassKt.kt) && " + 
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
+          "$(location EvilNamesProto3Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
+          "$(location HardKeywordsAllTypesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+kt_jvm_library(
+    name = "kotlin_unittest_lite",
+    srcs = [
+        ":gen_evil_names_proto2_lite",
+        "//:gen_kotlin_unittest_lite",
+    ],
+    deps = [
+        ":evil_names_proto2_java_proto_lite",
+        "//java/lite:lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "//:java_lite_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "kotlin_proto3_unittest_lite",
+    srcs = [
+        ":gen_evil_names_proto3_lite",
+        ":gen_kotlin_proto3_java_multiple_files_lite",
+        "//:gen_kotlin_proto3_unittest_lite",
+    ],
+    deps = [
+        ":evil_names_proto3_java_proto_lite",
+        ":multiple_files_proto3_java_proto_lite",
+        "//java/lite:lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "//:java_lite_test_protos",
+    ],
+)
+
+kt_jvm_test(
+    name = "proto2_test_lite",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt"],
+    deps = [
+        ":kotlin_unittest_lite",
+        "//java/core:test_util_lite",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.Proto2LiteTest",
+)
+
+kt_jvm_test(
+    name = "proto3_test_lite",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto3LiteTest.kt"],
+    deps = [
+        ":kotlin_proto3_unittest_lite",
+        "//java/core:test_util_lite",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.Proto3LiteTest",
+)
diff --git a/java/kotlin-lite/generate-test-sources-build.xml b/java/kotlin-lite/generate-test-sources-build.xml
index c5f60b8..ed88620 100644
--- a/java/kotlin-lite/generate-test-sources-build.xml
+++ b/java/kotlin-lite/generate-test-sources-build.xml
@@ -12,7 +12,7 @@
         <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.source.dir}/google/protobuf/unittest_proto3_lite.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"/>
@@ -25,7 +25,7 @@
       <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.source.dir}/google/protobuf/unittest_proto3_lite.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"/>
diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml
index 0348bdd..2c33cc8 100644
--- a/java/kotlin-lite/pom.xml
+++ b/java/kotlin-lite/pom.xml
@@ -9,9 +9,9 @@
 
   <artifactId>protobuf-kotlin-lite</artifactId>
 
-  <name>Protocol Buffers [Lite]</name>
+  <name>Protocol Buffers [Kotlin-Lite]</name>
   <description>
-    Lite version of Protocol Buffers library. This version is optimized for code size, but does
+    Lite version of Kotlin Protocol Buffers library. This version is optimized for code size, but does
     not guarantee API/ABI stability.
   </description>
 
diff --git a/java/kotlin-lite/pom_template.xml b/java/kotlin-lite/pom_template.xml
new file mode 100644
index 0000000..d5e513e
--- /dev/null
+++ b/java/kotlin-lite/pom_template.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>{groupId}</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>{version}</version>
+  </parent>
+
+  <artifactId>{artifactId}</artifactId>
+  <packaging>{type}</packaging>
+
+  <name>Protocol Buffers [Kotlin lite]</name>
+  <description>
+    Kotlin lite Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <properties>
+    <kotlin.version>1.5.0</kotlin.version>
+  </properties>
+</project>
diff --git a/java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt b/java/kotlin-lite/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt
similarity index 100%
rename from java/kotlin/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt
rename to java/kotlin-lite/src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt
diff --git a/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto3LiteTest.kt b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto3LiteTest.kt
new file mode 100644
index 0000000..8d3680a
--- /dev/null
+++ b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto3LiteTest.kt
@@ -0,0 +1,365 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.Class
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.EvilNamesProto3
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.HardKeywordsAllTypesProto3
+import com.google.protobuf.kotlin.generator.HardKeywordsAllTypesProto3Kt
+import com.google.protobuf.kotlin.generator.class_
+import com.google.protobuf.kotlin.generator.evilNamesProto3
+import com.google.protobuf.kotlin.generator.hardKeywordsAllTypesProto3
+import proto3_lite_unittest.TestAllTypesKt
+import proto3_lite_unittest.TestAllTypesKt.nestedMessage
+import proto3_lite_unittest.UnittestProto3Lite.TestAllTypes
+import proto3_lite_unittest.UnittestProto3Lite.TestAllTypes.NestedEnum
+import proto3_lite_unittest.UnittestProto3Lite.TestEmptyMessage
+import proto3_lite_unittest.copy
+import proto3_lite_unittest.testAllTypes
+import proto3_lite_unittest.testEmptyMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto3LiteTest {
+  @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() {
+    hardKeywordsAllTypesProto3 {
+      as_ = 1
+      assertThat(as_).isEqualTo(1)
+
+      in_ = "foo"
+      assertThat(in_).isEqualTo("foo")
+
+      break_ = HardKeywordsAllTypesProto3.NestedEnum.FOO
+      assertThat(break_).isEqualTo(HardKeywordsAllTypesProto3.NestedEnum.FOO)
+
+      do_ = HardKeywordsAllTypesProto3Kt.nestedMessage { while_ = 1 }
+      assertThat(do_).isEqualTo(HardKeywordsAllTypesProto3Kt.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_ += HardKeywordsAllTypesProto3.NestedEnum.FOO
+      assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypesProto3.NestedEnum.FOO))
+
+      if_ += HardKeywordsAllTypesProto3Kt.nestedMessage { while_ = 1 }
+      assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesProto3Kt.nestedMessage { while_ = 1 }))
+    }
+  }
+
+  @Test
+  fun testHardKeywordHazzers() {
+    hardKeywordsAllTypesProto3 {
+      as_ = 1
+      assertThat(hasAs_()).isTrue()
+
+      in_ = "foo"
+      assertThat(hasIn_()).isTrue()
+
+      break_ = HardKeywordsAllTypesProto3.NestedEnum.FOO
+      assertThat(hasBreak_()).isTrue()
+
+      do_ = HardKeywordsAllTypesProto3Kt.nestedMessage { while_ = 1 }
+      assertThat(hasDo_()).isTrue()
+    }
+  }
+
+  @Test
+  fun testHardKeywordClears() {
+    hardKeywordsAllTypesProto3 {
+      as_ = 1
+      clearAs_()
+      assertThat(hasAs_()).isFalse()
+
+      in_ = "foo"
+      clearIn_()
+      assertThat(hasIn_()).isFalse()
+
+      break_ = HardKeywordsAllTypesProto3.NestedEnum.FOO
+      clearBreak_()
+      assertThat(hasBreak_()).isFalse()
+
+      do_ = HardKeywordsAllTypesProto3Kt.nestedMessage { while_ = 1 }
+      clearDo_()
+      assertThat(hasDo_()).isFalse()
+    }
+  }
+
+  @Test
+  fun testMultipleFiles() {
+    assertThat(
+      com.google.protobuf.kotlin.generator.multipleFilesMessageA {}
+    ).isEqualTo(
+      com.google.protobuf.kotlin.generator.MultipleFilesMessageA.newBuilder().build()
+    )
+
+    assertThat(
+      com.google.protobuf.kotlin.generator.multipleFilesMessageB {}
+    ).isEqualTo(
+      com.google.protobuf.kotlin.generator.MultipleFilesMessageB.newBuilder().build()
+    )
+  }
+}
diff --git a/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto
new file mode 100644
index 0000000..3735baf
--- /dev/null
+++ b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// LINT: LEGACY_NAMES
+syntax = "proto2";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+
+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 HardKeywordsAllTypesProto2 {
+  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-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto
new file mode 100644
index 0000000..f6b06d3
--- /dev/null
+++ b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto
@@ -0,0 +1,107 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// LINT: LEGACY_NAMES
+syntax = "proto3";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+
+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 HardKeywordsAllTypesProto3 {
+  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-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
new file mode 100644
index 0000000..61141c5
--- /dev/null
+++ b/java/kotlin-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+option java_multiple_files = true;
+
+enum NestedEnum { FOO = 0; }
+
+message MultipleFilesMessageA {}
+
+message MultipleFilesMessageB {}
diff --git a/java/kotlin/BUILD b/java/kotlin/BUILD
new file mode 100644
index 0000000..97c8162
--- /dev/null
+++ b/java/kotlin/BUILD
@@ -0,0 +1,278 @@
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library", "kt_jvm_test", "kt_jvm_binary")
+load("@rules_java//java:defs.bzl", "java_proto_library")
+load("@rules_jvm_external//:defs.bzl", "java_export")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("//:protobuf_version.bzl", "PROTOBUF_VERSION")
+
+# Kotlin generated protos depend on this and only this.
+kt_jvm_library(
+    name = "shared_runtime",
+    srcs = [
+        "src/main/kotlin/com/google/protobuf/DslList.kt",
+        "src/main/kotlin/com/google/protobuf/DslMap.kt",
+        "src/main/kotlin/com/google/protobuf/DslProxy.kt",
+        "src/main/kotlin/com/google/protobuf/ExtensionList.kt",
+        "src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt",
+        "src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/lite",
+    ],
+)
+
+kt_jvm_library(
+    name = "only_for_use_in_proto_generated_code_its_generator_and_tests",
+    srcs = ["src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt"],
+    visibility = ["//java:__subpackages__"],
+)
+
+kt_jvm_library(
+    name = "bytestring_lib",
+    srcs = ["src/main/kotlin/com/google/protobuf/ByteStrings.kt"],
+    deps = ["//java/lite"],
+)
+
+kt_jvm_library(
+    name = "full_extensions",
+    srcs = ["src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt"],
+    deps = ["//java/core"],
+)
+
+test_suite(
+    name = "tests",
+    tests = [
+        "bytestring_test",
+        "shared_tests",
+        "test_extensions",
+        "proto2_test",
+        "proto3_test",
+    ],
+)
+
+kt_jvm_test(
+    name = "bytestring_test",
+    srcs = ["src/test/kotlin/com/google/protobuf/ByteStringsTest.kt"],
+    deps = [
+        ":bytestring_lib",
+        "//java/lite",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.ByteStringsTest",
+)
+
+proto_library(
+    name = "example_extensible_message_proto",
+    srcs = ["src/test/proto/com/google/protobuf/example_extensible_message.proto"],
+    visibility = ["//visibility:public"],
+)
+
+java_proto_library(
+    name = "example_extensible_message_java_proto",
+    deps = [":example_extensible_message_proto"],
+)
+
+kt_jvm_test(
+    name = "shared_tests",
+    srcs = [
+        "src/test/kotlin/com/google/protobuf/DslListTest.kt",
+        "src/test/kotlin/com/google/protobuf/DslMapTest.kt",
+        "src/test/kotlin/com/google/protobuf/ExtensionListTest.kt",
+    ],
+    deps = [
+        ":bytestring_lib",
+        ":example_extensible_message_java_proto",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:com_google_guava_guava_testlib",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.DslListTest",
+)
+
+kt_jvm_test(
+    name = "test_extensions",
+    srcs = ["src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt"],
+    deps = [
+        ":example_extensible_message_java_proto",
+        ":full_extensions",
+        "//java/lite",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.ExtendableMessageExtensionsTest",
+)
+
+proto_library(
+    name = "evil_names_proto2",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+proto_library(
+    name = "evil_names_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+java_proto_library(
+    name = "evil_names_proto2_java_proto",
+    deps = [":evil_names_proto2"],
+)
+
+java_proto_library(
+    name = "evil_names_proto3_java_proto",
+    deps = [":evil_names_proto3"],
+)
+
+proto_library(
+    name = "multiple_files_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+java_proto_library( name = "multiple_files_proto3_java_proto",
+    deps = [":multiple_files_proto3"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_java_multiple_files",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    outs = [
+        "MultipleFilesMessageAKt.kt",
+        "MultipleFilesMessageBKt.kt",
+        "MultipleFilesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
+          "$(location MultipleFilesMessageAKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
+          "$(location MultipleFilesMessageBKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
+          "$(location MultipleFilesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto2",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    outs = [
+        "EvilNamesProto2Kt.kt",
+        "HardKeywordsAllTypesProto2Kt.kt",
+        "InterfaceKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
+          "$(location EvilNamesProto2Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
+          "$(location HardKeywordsAllTypesProto2Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
+          "$(location InterfaceKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    outs = [
+        "ClassKt.kt",
+        "EvilNamesProto3Kt.kt",
+        "HardKeywordsAllTypesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
+          "$(location ClassKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
+          "$(location EvilNamesProto3Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
+          "$(location HardKeywordsAllTypesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+kt_jvm_library(
+    name = "kotlin_unittest",
+    srcs = [
+        ":gen_evil_names_proto2",
+        "//:gen_kotlin_unittest",
+    ],
+    deps = [
+        ":evil_names_proto2_java_proto",
+        "//java/core:core",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "//:java_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "kotlin_proto3_unittest",
+    srcs = [
+        ":gen_evil_names_proto3",
+        ":gen_kotlin_proto3_java_multiple_files",
+        "//:gen_kotlin_proto3_unittest",
+    ],
+    deps = [
+        ":evil_names_proto3_java_proto",
+        ":multiple_files_proto3_java_proto",
+        "//java/core:core",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "//:java_test_protos",
+    ],
+)
+
+kt_jvm_test(
+    name = "proto2_test",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto2Test.kt"],
+    deps = [
+        ":kotlin_unittest",
+        "//java/core:test_util",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.Proto2Test",
+)
+
+kt_jvm_test(
+    name = "proto3_test",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto3Test.kt"],
+    deps = [
+        ":kotlin_proto3_unittest",
+        "//java/core:test_util",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+    test_class = "com.google.protobuf.kotlin.Proto3Test",
+)
+
+java_export(
+    name = "kotlin_mvn",
+    maven_coordinates = "com.google.protobuf:protobuf-kotlin:%s" % PROTOBUF_VERSION,
+    pom_template = "pom_template.xml",
+    runtime_deps = [":shared_runtime"],
+)
+
+filegroup(
+    name = "release",
+    srcs = [
+        ":kotlin_mvn-docs",
+        ":kotlin_mvn-maven-source",
+        ":kotlin_mvn-pom",
+        ":kotlin_mvn-project",
+    ],
+    visibility = ["//java:__pkg__"],
+)
diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml
index a275f24..4157a53 100644
--- a/java/kotlin/pom.xml
+++ b/java/kotlin/pom.xml
@@ -9,9 +9,9 @@
 
   <artifactId>protobuf-kotlin</artifactId>
 
-  <name>Protocol Buffers [Core]</name>
+  <name>Protocol Buffers [Kotlin-Core]</name>
   <description>
-    Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    Kotlin core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
     efficient yet extensible format.
   </description>
 
diff --git a/java/kotlin/pom_template.xml b/java/kotlin/pom_template.xml
new file mode 100644
index 0000000..3231fb3
--- /dev/null
+++ b/java/kotlin/pom_template.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>{groupId}</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>{version}</version>
+  </parent>
+
+  <artifactId>{artifactId}</artifactId>
+  <packaging>{type}</packaging>
+
+  <name>Protocol Buffers [Kotlin]</name>
+  <description>
+    Kotlin core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <properties>
+    <kotlin.version>1.5.0</kotlin.version>
+  </properties>
+
+</project>
diff --git a/maven_install.json b/maven_install.json
index 3919de3..bce3e2b 100644
--- a/maven_install.json
+++ b/maven_install.json
@@ -1,11 +1,11 @@
 {
     "dependency_tree": {
         "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
-        "__INPUT_ARTIFACTS_HASH": -1650978854,
-        "__RESOLVED_ARTIFACTS_HASH": -718494898,
+        "__INPUT_ARTIFACTS_HASH": 1634601905,
+        "__RESOLVED_ARTIFACTS_HASH": -143733866,
         "conflict_resolution": {
             "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1",
-            "junit:junit:4.12": "junit:junit:4.13.1"
+            "junit:junit:4.12": "junit:junit:4.13.2"
         },
         "dependencies": [
             {
@@ -81,6 +81,35 @@
                 "url": "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar"
             },
             {
+                "coord": "com.google.guava:guava-testlib:30.1.1-jre",
+                "dependencies": [
+                    "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
+                    "com.google.j2objc:j2objc-annotations:1.3",
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "org.hamcrest:hamcrest-core:1.3",
+                    "com.google.guava:guava:30.1.1-jre",
+                    "com.google.guava:failureaccess:1.0.1",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
+                    "org.checkerframework:checker-qual:3.9.1"
+                ],
+                "directDependencies": [
+                    "com.google.j2objc:j2objc-annotations:1.3",
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "com.google.guava:guava:30.1.1-jre",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
+                    "org.checkerframework:checker-qual:3.9.1"
+                ],
+                "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar",
+                "mirror_urls": [
+                    "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar",
+                    "https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar"
+                ],
+                "sha256": "8a7fc9adfa1e7441d1d30ca288c593ebc7c4a24c601d01169b781c398f24099b",
+                "url": "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar"
+            },
+            {
                 "coord": "com.google.guava:guava:30.1.1-jre",
                 "dependencies": [
                     "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
@@ -134,19 +163,18 @@
                 "coord": "com.google.truth:truth:1.1.2",
                 "dependencies": [
                     "org.ow2.asm:asm:9.0",
-                    "org.hamcrest:hamcrest-core:1.3",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "junit:junit:4.13.1",
                     "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "directDependencies": [
                     "org.ow2.asm:asm:9.0",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "junit:junit:4.13.1",
                     "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "file": "v1/https/repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar",
@@ -158,20 +186,20 @@
                 "url": "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar"
             },
             {
-                "coord": "junit:junit:4.13.1",
+                "coord": "junit:junit:4.13.2",
                 "dependencies": [
                     "org.hamcrest:hamcrest-core:1.3"
                 ],
                 "directDependencies": [
                     "org.hamcrest:hamcrest-core:1.3"
                 ],
-                "file": "v1/https/repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar",
+                "file": "v1/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar",
                 "mirror_urls": [
-                    "https://repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar",
-                    "https://repo.maven.apache.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar"
+                    "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar",
+                    "https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
                 ],
-                "sha256": "c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122",
-                "url": "https://repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar"
+                "sha256": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3",
+                "url": "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
             },
             {
                 "coord": "org.checkerframework:checker-qual:3.9.1",
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index f780068..6f26a90 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -8,6 +8,7 @@
     "com.google.errorprone:error_prone_annotations:2.3.2",
     "com.google.j2objc:j2objc-annotations:1.3",
     "com.google.guava:guava:30.1.1-jre",
+    "com.google.guava:guava-testlib:30.1.1-jre",
     "com.google.truth:truth:1.1.2",
     "junit:junit:4.12",
     "org.easymock:easymock:3.2",