diff options
author | Jiayu Liu <Jimexist@users.noreply.github.com> | 2022-05-07 00:40:03 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-06 12:40:03 -0400 |
commit | 6c002b61e591b712fca2713eefd3e99c5782bb21 (patch) | |
tree | 3c3bb2423982531edd4721a1c76b6723754a0a30 | |
parent | 53ec08228a14130909d4dd6fc2c98f47a09d76b0 (diff) | |
download | thrift-6c002b61e591b712fca2713eefd3e99c5782bb21.tar.gz |
THRIFT-5571: add metadata map building to kotlin generator (#2584)
-rw-r--r-- | compiler/cpp/src/thrift/generate/t_kotlin_generator.cc | 101 | ||||
-rwxr-xr-x | configure.ac | 4 | ||||
-rw-r--r-- | lib/kotlin/Makefile.am | 2 | ||||
-rw-r--r-- | lib/kotlin/build.gradle.kts | 76 | ||||
-rw-r--r-- | lib/kotlin/cross-test-client/build.gradle.kts | 6 | ||||
-rw-r--r-- | lib/kotlin/cross-test-client/src/main/kotlin/org/apache/thrift/test/TestClient.kt | 76 | ||||
-rw-r--r-- | lib/kotlin/cross-test-server/build.gradle.kts | 6 | ||||
-rw-r--r-- | lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestServer.kt | 13 | ||||
-rw-r--r-- | lib/kotlin/settings.gradle.kts | 6 | ||||
-rw-r--r-- | lib/kotlin/src/test/kotlin/org/apache/thrift/MetaDataTest.kt | 42 | ||||
-rw-r--r-- | lib/kotlin/src/test/resources/AnnotationTest.thrift | 7 |
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 +} |