summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiayu Liu <Jimexist@users.noreply.github.com>2022-05-07 00:40:03 +0800
committerGitHub <noreply@github.com>2022-05-06 12:40:03 -0400
commit6c002b61e591b712fca2713eefd3e99c5782bb21 (patch)
tree3c3bb2423982531edd4721a1c76b6723754a0a30
parent53ec08228a14130909d4dd6fc2c98f47a09d76b0 (diff)
downloadthrift-6c002b61e591b712fca2713eefd3e99c5782bb21.tar.gz
THRIFT-5571: add metadata map building to kotlin generator (#2584)
-rw-r--r--compiler/cpp/src/thrift/generate/t_kotlin_generator.cc101
-rwxr-xr-xconfigure.ac4
-rw-r--r--lib/kotlin/Makefile.am2
-rw-r--r--lib/kotlin/build.gradle.kts76
-rw-r--r--lib/kotlin/cross-test-client/build.gradle.kts6
-rw-r--r--lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt76
-rw-r--r--lib/kotlin/cross-test-server/build.gradle.kts6
-rw-r--r--lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt13
-rw-r--r--lib/kotlin/settings.gradle.kts6
-rw-r--r--lib/kotlin/src/test/kotlin/org/apache/thrift/MetaDataTest.kt42
-rw-r--r--lib/kotlin/src/test/resources/AnnotationTest.thrift7
11 files changed, 285 insertions, 54 deletions
diff --git a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
index 21f13a816..28477ba9a 100644
--- a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
@@ -152,6 +152,8 @@ private:
std::string additional_interface = "");
void generate_struct_field_name_constants(std::ostream& out, t_struct* tstruct);
void generate_struct_companion_object(std::ostream& out, t_struct* tstruct);
+ void generate_field_value_meta_data(std::ostream& out, t_type* ttype);
+ void generate_metadata_for_field_annotations(std::ostream& out, t_field* tfield);
void generate_struct_standard_scheme(std::ostream& out, t_struct* tstruct);
void generate_struct_standard_scheme_read(std::ostream& out, t_struct* tstruct);
void generate_struct_standard_scheme_write(std::ostream& out, t_struct* tstruct);
@@ -633,18 +635,117 @@ void t_kotlin_generator::generate_struct_companion_object(std::ostream& out, t_s
<< tstruct->get_name() << "\")" << endl;
{
for (auto& field : tstruct->get_members()) {
+ // field desc
indent(out) << "private val " << constant_name(field->get_name())
<< "_FIELD_DESC: org.apache.thrift.protocol.TField = "
"org.apache.thrift.protocol.TField(\""
<< field->get_name() << "\", " << type_to_enum(field->get_type()) << ", "
<< field->get_key() << ")" << endl;
+ // field metadata
+ indent(out) << "private val " << constant_name(field->get_name())
+ << "_FIELD_META_DATA: org.apache.thrift.meta_data.FieldMetaData = "
+ "org.apache.thrift.meta_data.FieldMetaData("
+ << endl;
+ indent_up();
+ {
+ indent(out) << '"' << field->get_name() << '"' << ',' << endl;
+ indent(out) << "org.apache.thrift.TFieldRequirementType.";
+ if (field->get_req() == t_field::T_REQUIRED) {
+ out << "REQUIRED";
+ } else if (field->get_req() == t_field::T_OPTIONAL) {
+ out << "OPTIONAL";
+ } else {
+ out << "DEFAULT";
+ }
+ out << ',' << endl;
+ generate_field_value_meta_data(indent(out), field->get_type());
+ out << ',' << endl;
+ generate_metadata_for_field_annotations(indent(out), field);
+ }
+ out << ")" << endl;
+ indent_down();
}
}
+
+ // all fields in a map
+ indent(out)
+ << "private val metadata: Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> = mapOf("
+ << endl;
+ indent_up();
+ for (auto& field : tstruct->get_members()) {
+ indent(out) << "_Fields." << constant_name(field->get_name()) << " to "
+ << constant_name(field->get_name()) << "_FIELD_META_DATA," << endl;
+ }
+ indent_down();
+ indent(out) << ")" << endl;
+
+ indent(out) << "init {" << endl;
+ indent_up();
+ indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap("
+ << tstruct->get_name() << "::class.java, metadata)" << endl;
+ scope_down(out);
}
scope_down(out);
out << endl;
}
+void t_kotlin_generator::generate_metadata_for_field_annotations(std::ostream& out,
+ t_field* field) {
+ if (field->annotations_.size() == 0) {
+ out << "emptyMap()";
+ } else {
+ out << "mapOf(" << endl;
+ indent_up();
+ for (auto& annotation : field->annotations_) {
+ indent(out) << "\"" + annotation.first + "\" to \"" + annotation.second + "\"," << endl;
+ }
+ indent_down();
+ indent(out) << ")";
+ }
+}
+
+void t_kotlin_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
+ static const string ttype_class = "org.apache.thrift.protocol.TType.";
+ static const string meta_package = "org.apache.thrift.meta_data.";
+ out << meta_package;
+ if (type->is_struct() || type->is_xception()) {
+ out << "StructMetaData(" << ttype_class << "STRUCT, " << type_name(type) << "::class.java";
+ } else if (type->is_container()) {
+ if (type->is_list()) {
+ out << "ListMetaData(" << ttype_class << "LIST," << endl;
+ indent_up();
+ t_type* elem_type = ((t_list*)type)->get_elem_type();
+ generate_field_value_meta_data(indent(out), elem_type);
+ indent_down();
+ } else if (type->is_set()) {
+ out << "SetMetaData(" << ttype_class << "SET," << endl;
+ indent_up();
+ t_type* elem_type = ((t_set*)type)->get_elem_type();
+ generate_field_value_meta_data(indent(out), elem_type);
+ indent_down();
+ } else {
+ out << "MapMetaData(" << ttype_class << "MAP," << endl;
+ indent_up();
+ t_type* key_type = ((t_map*)type)->get_key_type();
+ t_type* val_type = ((t_map*)type)->get_val_type();
+ generate_field_value_meta_data(indent(out), key_type);
+ out << "," << endl;
+ generate_field_value_meta_data(indent(out), val_type);
+ indent_down();
+ }
+ } else if (type->is_enum()) {
+ out << "EnumMetaData(" << ttype_class << "ENUM, " << type_name(type) << "::class.java";
+ } else {
+ out << "FieldValueMetaData(" << type_to_enum(type);
+ if (type->is_typedef()) {
+ out << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
+ } else if (type->is_binary()) {
+ out << ", true";
+ }
+ }
+ out << ")";
+}
+
void t_kotlin_generator::generate_struct_method_deep_copy(std::ostream& out, t_struct* tstruct) {
indent(out) << "override fun deepCopy(): " << tstruct->get_name() << " {" << endl;
indent_up();
diff --git a/configure.ac b/configure.ac
index 624287b27..60b24892a 100755
--- a/configure.ac
+++ b/configure.ac
@@ -956,10 +956,10 @@ fi
if test "$have_kotlin" = "yes" ; then
echo
echo "Kotlin (Test Only) Library:"
- echo " Using gradlew ............. : lib/kotlin/gradlew"
+ echo " Using gradle .............. : $GRADLE"
echo " Using java ................ : $JAVA"
echo " Using javac ............... : $JAVAC"
- echo " Using Gradle version ...... : $(lib/kotlin/gradlew --version --quiet | grep Gradle 2>&1)"
+ echo " Using Gradle version ...... : $($GRADLE --version --quiet | grep Gradle 2>&1)"
echo " Using java version ........ : $($JAVA -version 2>&1 | grep 'version ')"
fi
if test "$have_lua" = "yes" ; then
diff --git a/lib/kotlin/Makefile.am b/lib/kotlin/Makefile.am
index 6a99628a2..f57fc33c1 100644
--- a/lib/kotlin/Makefile.am
+++ b/lib/kotlin/Makefile.am
@@ -22,7 +22,7 @@ export CLASSPATH
all-local:
$(GRADLE) $(GRADLE_OPTS) assemble \
-Pthrift.version=$(PACKAGE_VERSION) \
- -Pthrift.compiler=$(THRIFT) \
+ -Pthrift.compiler=$(THRIFT) \
--console=plain
clean-local:
diff --git a/lib/kotlin/build.gradle.kts b/lib/kotlin/build.gradle.kts
new file mode 100644
index 000000000..6e944b0e5
--- /dev/null
+++ b/lib/kotlin/build.gradle.kts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+plugins {
+ kotlin("jvm")
+ id("com.ncorti.ktfmt.gradle")
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+ // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-jdk8
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.1")
+ // https://mvnrepository.com/artifact/org.apache.thrift/libthrift
+ implementation("org.apache.thrift:libthrift:INCLUDED")
+ testImplementation(kotlin("test"))
+}
+
+tasks {
+ ktfmt {
+ kotlinLangStyle()
+ }
+
+ test {
+ useJUnitPlatform()
+ }
+
+ task<Exec>("compileThrift") {
+ val thriftBin = if (hasProperty("thrift.compiler")) {
+ file(property("thrift.compiler"))
+ } else {
+ project.rootDir.resolve("../../compiler/cpp/thrift")
+ }
+ val outputDir = layout.buildDirectory.dir("generated-sources")
+ doFirst {
+ mkdir(outputDir)
+ }
+ commandLine = listOf(
+ thriftBin.absolutePath,
+ "-gen",
+ "kotlin",
+ "-out",
+ outputDir.get().toString(),
+ layout.projectDirectory.file("src/test/resources/AnnotationTest.thrift").asFile.absolutePath
+ )
+ group = LifecycleBasePlugin.BUILD_GROUP
+ }
+
+ compileKotlin {
+ dependsOn("compileThrift")
+ }
+}
+
+sourceSets["main"].java {
+ srcDir(layout.buildDirectory.dir("generated-sources"))
+}
diff --git a/lib/kotlin/cross-test-client/build.gradle.kts b/lib/kotlin/cross-test-client/build.gradle.kts
index 3e67abfe5..e5f87dd69 100644
--- a/lib/kotlin/cross-test-client/build.gradle.kts
+++ b/lib/kotlin/cross-test-client/build.gradle.kts
@@ -18,8 +18,8 @@
*/
plugins {
- kotlin("jvm") version "1.5.31"
- id("com.ncorti.ktfmt.gradle") version "0.4.0"
+ kotlin("jvm")
+ id("com.ncorti.ktfmt.gradle")
java
application
}
@@ -37,8 +37,6 @@ dependencies {
implementation("org.apache.thrift:libthrift:INCLUDED")
// https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
implementation("ch.qos.logback:logback-classic:1.3.0-alpha14")
- testImplementation("org.jetbrains.kotlin:kotlin-test")
- testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
tasks {
diff --git a/lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt b/lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt
index 10ca82927..7597f2f8b 100644
--- a/lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt
+++ b/lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt
@@ -18,6 +18,9 @@
*/
package org.apache.thrift.test
+import java.nio.ByteBuffer
+import kotlin.math.abs
+import kotlin.system.exitProcess
import org.apache.http.impl.client.HttpClients
import org.apache.thrift.TApplicationException
import org.apache.thrift.TException
@@ -43,9 +46,6 @@ import thrift.test.Xception
import thrift.test.Xception2
import thrift.test.Xtruct
import thrift.test.Xtruct2
-import java.nio.ByteBuffer
-import kotlin.math.abs
-import kotlin.system.exitProcess
/**
* Test Java client for thrift. Essentially just a copy of the C++ version, this makes a variety of
@@ -739,13 +739,13 @@ suspend fun main(args: Array<String>) {
val m1 = mm[4]!!
val m2 = mm[-4]!!
if (m1[1] != 1 ||
- m1[2] != 2 ||
- m1[3] != 3 ||
- m1[4] != 4 ||
- m2[-1] != -1 ||
- m2[-2] != -2 ||
- m2[-3] != -3 ||
- m2[-4] != -4
+ m1[2] != 2 ||
+ m1[3] != 3 ||
+ m1[4] != 4 ||
+ m2[-1] != -1 ||
+ m2[-2] != -2 ||
+ m2[-3] != -3 ||
+ m2[-4] != -4
) {
returnCode = returnCode or ERR_CONTAINERS
println("*** FAILURE ***\n")
@@ -810,12 +810,12 @@ suspend fun main(args: Array<String>) {
val first_map = whoa[1L]!!
val second_map = whoa[2L]!!
if (first_map.size == 2 &&
- first_map.containsKey(Numberz.TWO) &&
- first_map.containsKey(Numberz.THREE) &&
- second_map.size == 1 &&
- second_map.containsKey(Numberz.SIX) &&
- insane == first_map[Numberz.TWO] &&
- insane == first_map[Numberz.THREE]
+ first_map.containsKey(Numberz.TWO) &&
+ first_map.containsKey(Numberz.THREE) &&
+ second_map.size == 1 &&
+ second_map.containsKey(Numberz.SIX) &&
+ insane == first_map[Numberz.TWO] &&
+ insane == first_map[Numberz.THREE]
) {
val six = second_map[Numberz.SIX]!!
// Cannot use "new Insanity().equals(six)" because as of now,
@@ -901,8 +901,8 @@ suspend fun main(args: Array<String>) {
if (onewayElapsedMillis > 200) {
println(
"Oneway test took too long to execute failed: took " +
- onewayElapsedMillis +
- "ms"
+ onewayElapsedMillis +
+ "ms"
)
println(
"oneway calls are 'fire and forget' and therefore should not cause blocking."
@@ -1011,29 +1011,31 @@ private fun getTTransport(
}
}
else -> {
- val socket = if (ssl) {
- TSSLTransportFactory.getClientSocket(host, port, socketTimeout)
- } else {
- println("using non-blocking socket $host:$port")
- TNonblockingSocket(host, port, socketTimeout)
- }
+ val socket =
+ if (ssl) {
+ TSSLTransportFactory.getClientSocket(host, port, socketTimeout)
+ } else {
+ println("using non-blocking socket $host:$port")
+ TNonblockingSocket(host, port, socketTimeout)
+ }
if (transport_type == "zlib") {
return TZlibTransport(socket)
} else {
- val wrapped = when (transport_type) {
- "buffered" -> {
- socket
- }
- "framed" -> {
- TFramedTransport(socket)
- }
- "fastframed" -> {
- TFastFramedTransport(socket)
- }
- else -> {
- socket
+ val wrapped =
+ when (transport_type) {
+ "buffered" -> {
+ socket
+ }
+ "framed" -> {
+ TFramedTransport(socket)
+ }
+ "fastframed" -> {
+ TFastFramedTransport(socket)
+ }
+ else -> {
+ socket
+ }
}
- }
return if (zlib) {
TZlibTransport(wrapped)
} else {
diff --git a/lib/kotlin/cross-test-server/build.gradle.kts b/lib/kotlin/cross-test-server/build.gradle.kts
index 6b20de112..8a654d955 100644
--- a/lib/kotlin/cross-test-server/build.gradle.kts
+++ b/lib/kotlin/cross-test-server/build.gradle.kts
@@ -18,8 +18,8 @@
*/
plugins {
- kotlin("jvm") version "1.5.31"
- id("com.ncorti.ktfmt.gradle") version "0.4.0"
+ kotlin("jvm")
+ id("com.ncorti.ktfmt.gradle")
java
application
}
@@ -37,8 +37,6 @@ dependencies {
implementation("org.apache.thrift:libthrift:INCLUDED")
// https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
implementation("ch.qos.logback:logback-classic:1.3.0-alpha14")
- testImplementation("org.jetbrains.kotlin:kotlin-test")
- testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
tasks {
diff --git a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt
index b04548d79..4b2bdff7c 100644
--- a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt
+++ b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt
@@ -143,7 +143,7 @@ fun main(args: Array<String>) {
var zlib = false
var transportType = "buffered"
var protocolType = "binary"
-// var serverType = "thread-pool"
+ // var serverType = "thread-pool"
var serverType = "nonblocking"
val domainSocket = ""
var stringLimit: Long = -1
@@ -308,11 +308,12 @@ fun main(args: Array<String>) {
// Blocking servers
// SSL socket
- val tServerSocket: TServerSocket = if (ssl) {
- TSSLTransportFactory.getServerSocket(port, 0)
- } else {
- TServerSocket(ServerSocketTransportArgs().port(port))
- }
+ val tServerSocket: TServerSocket =
+ if (ssl) {
+ TSSLTransportFactory.getServerSocket(port, 0)
+ } else {
+ TServerSocket(ServerSocketTransportArgs().port(port))
+ }
if (serverType == "simple") {
// Simple Server
val tServerArgs = TServer.Args(tServerSocket)
diff --git a/lib/kotlin/settings.gradle.kts b/lib/kotlin/settings.gradle.kts
index f412707d4..a6bdbbca6 100644
--- a/lib/kotlin/settings.gradle.kts
+++ b/lib/kotlin/settings.gradle.kts
@@ -16,6 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
+pluginManagement {
+ plugins {
+ kotlin("jvm") version "1.5.31"
+ id("com.ncorti.ktfmt.gradle") version "0.4.0"
+ }
+}
rootProject.name = "libthrift-kotlin"
diff --git a/lib/kotlin/src/test/kotlin/org/apache/thrift/MetaDataTest.kt b/lib/kotlin/src/test/kotlin/org/apache/thrift/MetaDataTest.kt
new file mode 100644
index 000000000..e066bbe4d
--- /dev/null
+++ b/lib/kotlin/src/test/kotlin/org/apache/thrift/MetaDataTest.kt
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift
+
+import kotlin.test.assertEquals
+import org.apache.thrift.kotlin.annotation.test.Person
+import org.apache.thrift.meta_data.FieldMetaData
+import org.junit.jupiter.api.Test
+
+internal class MetaDataTest {
+ @Test
+ internal fun testAnnotation() {
+ val personMetadata = FieldMetaData.getStructMetaDataMap(Person::class.java)
+ assertEquals(3, personMetadata.size)
+ val idField = personMetadata[Person._Fields.ID]!!
+ assertEquals("id", idField.fieldName)
+ assertEquals(
+ mapOf(
+ "max" to "100000",
+ "min" to "1",
+ ),
+ idField.fieldAnnotations
+ )
+ }
+}
diff --git a/lib/kotlin/src/test/resources/AnnotationTest.thrift b/lib/kotlin/src/test/resources/AnnotationTest.thrift
new file mode 100644
index 000000000..0c4bca205
--- /dev/null
+++ b/lib/kotlin/src/test/resources/AnnotationTest.thrift
@@ -0,0 +1,7 @@
+namespace java org.apache.thrift.kotlin.annotation.test
+
+struct Person {
+ 1: required i64 id (min="1", max="100000")
+ 2: required string name
+ 3: optional string phoneNumber
+}