Practical Guide to Kotlin DSL: Applications, Examples, and Building Your Own DSL
This article introduces Kotlin DSL concepts, demonstrates real‑world applications such as Trip.com payment network encapsulation, overseas payment SDK Gradle scripts, Anko layouts, and provides a step‑by‑step example for creating a custom DSL, highlighting benefits, trade‑offs, and best practices for mobile development.
Kotlin DSL (Domain Specific Language) is a concise way to express domain‑specific logic, reducing boilerplate and improving readability, even for developers unfamiliar with the underlying language.
1. Introduction – DSLs can be external (stand‑alone syntax like XML/JSON) or internal (built on a host language). The article focuses on internal DSLs built with Kotlin.
2. Applications
2.1 Trip.com payment network encapsulation – Kotlin DSL is used to simplify request configuration and response handling. Example code:
fun requestBean(request: () -> BusinessBean) {
payClientBuilder.setRequestBean(request())
}
fun needRetry(needRetry: () -> Boolean) {
payClientBuilder.setNeedRetry(needRetry())
}
private var callSubSuccess: ((T) -> Unit)? = null
private var callSubFailed: ((Client.Error?) -> Unit)? = null
private var subCallback: PayNetCallback<T> = object : PayNetCallback<T> {
override fun onSucceed(response: T) { callSubSuccess?.invoke(response) }
override fun onFailed(error: Client.Error?) { callSubFailed?.invoke(error) }
}
fun subSuccess(subSuccess: (T) -> Unit) { callSubSuccess = subSuccess; payClientBuilder.setSubCallBack(subCallback) }
fun subFailed(subFailed: (Client.Error?) -> Unit) { callSubFailed = subFailed; payClientBuilder.setSubCallBack(subCallback) }
object PayNetworkClient {
fun <T : BusinessBean> init(costClass: Class<T>, config: PayClientConfigBuilder<T>.() -> Unit): PayClientBuilder.NetworkClient? {
var networkClient: PayClientBuilder.NetworkClient?
with(PayClientConfigBuilder(costClass)) { networkClient = build(config) }
return networkClient
}
}
val networkClient = PayNetworkClient.init(BusinessResponse::class.java) {
requestBean { request }
needRetry { false }
cancelOtherSession { "sendGetPayInfo" }
subSuccess { serviceSuccess(it) }
subFailed { serviceFailed(it) }
}
networkClient?.send()This DSL reduces repetitive code while keeping configuration flexible.
2.2 Overseas payment SDK Gradle DSL – Kotlin DSL replaces Groovy scripts, offering better IDE support. Sample Gradle script:
plugins {
id("com.android.application")
kotlin("android")
kotlin("android.extensions")
}
android {
compileSdkVersion(28)
defaultConfig {
applicationId = "trip.pay.app"
minSdkVersion(21)
targetSdkVersion(28)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
getByName("release") { isMinifyEnabled = true; proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") }
}
}
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation(kotlin("stdlib-jdk8", KotlinCompilerVersion.VERSION))
implementation("com.android.support:appcompat-v7:28.0.0")
implementation("com.android.support.constraint:constraint-layout:1.1.3")
implementation(project(":TripPay"))
}
repositories { mavenLocal(); maven(url = "maven地址") }Conversion effort from Groovy to Kotlin is modest, and build times are comparable.
2.3 Anko Layouts – Anko provides Kotlin‑based UI DSL, replacing verbose XML. Example XML vs. Anko:
<!-- XML example omitted for brevity -->
verticalLayout {
setGravity(Gravity.CENTER_VERTICAL)
editText { hintResource = R.string.main_edit_hint }.lparams(width = matchParent, height = wrapContent)
button {
textResource = R.string.main_button_text
onClick { toast("click!") }
}.lparams(width = matchParent, height = wrapContent)
}Anko reduces XML parsing overhead and offers type‑safe, concise UI code.
2.4 Creating a custom DSL – Using Kotlin’s extension functions, higher‑order functions, and infix notation, a simple DSL for building a Trip object is demonstrated:
data class Trip(var name: String? = "", var address: String? = "", var departments: List<Department>? = mutableListOf(), var city: List<String>? = mutableListOf(), var culture: String? = "")
data class Department(var name: String = "", var nameEn: String = "")
class TripBuilder {
var name: String? = ""
var address: String? = ""
val departments = mutableListOf<Department>()
fun department(block: DepartmentBuilder.() -> Unit) {
val builder = DepartmentBuilder()
block.invoke(builder)
departments.add(builder.build())
}
fun build(): Trip = Trip(name, address, departments)
}
class DepartmentBuilder { var name = ""; var nameEn = ""; fun build() = Department(name, nameEn) }
fun trip(block: TripBuilder.() -> Unit): Trip = TripBuilder().apply(block).build()
infix fun Trip.culture(culture: String) { this.culture = culture }
val trip = trip {
name = "Trip"
address = "上海市长宁区金钟路968号凌空SOHO"
department { name = "机票"; nameEn = "flight" }
department { name = "酒店"; nameEn = "hotel" }
department { name = "火车票"; nameEn = "train" }
}
trip culture "Customer、Teamwork、Respect、Integrity、Partner"
Log.i("result", trip)The DSL makes object construction expressive and reduces boilerplate, even for non‑Kotlin developers.
3. Conclusion – Kotlin DSLs are concise, improve readability, and can be safely adopted in production after weighing build‑time overhead; they are especially suitable for small to medium mobile projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
