Skip to content

Commit 8127833

Browse files
osipxdmarychatte
andauthored
KTOR-5085: Add multiplatform support for XML serialization (#4225)
* Make ktor-serialization-kotlinx-xml multiplatform * Disable JS browser target for server modules via gradle.properties --------- Co-authored-by: Mariia Skripchenko <[email protected]>
1 parent 16df081 commit 8127833

File tree

10 files changed

+81
-30
lines changed

10 files changed

+81
-30
lines changed

buildSrc/src/main/kotlin/JsConfig.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ fun Project.configureJs() {
2727
private fun Project.configureJsTasks() {
2828
kotlin {
2929
js {
30-
nodejs {
31-
testTask {
32-
useMocha {
33-
timeout = "10000"
30+
if (project.targetIsEnabled("js.nodeJs")) {
31+
nodejs {
32+
testTask {
33+
useMocha {
34+
timeout = "10000"
35+
}
3436
}
3537
}
3638
}

buildSrc/src/main/kotlin/NativeUtils.kt

+7-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,13 @@ fun Project.watchosTargets(): List<String> = with(kotlin) {
3838
watchosArm32(),
3939
watchosArm64(),
4040
watchosSimulatorArm64(),
41-
// because of dependency on YAML library: https://github.com/Him188/yamlkt/issues/67
42-
if (project.name != "ktor-server-config-yaml") watchosDeviceArm64() else null,
41+
// ktor-server-config-yaml: because of dependency on YAML library: https://github.com/Him188/yamlkt/issues/67
42+
// ktor-serialization-kotlinx-xml: because of dependency on xmlutil library: https://repo.maven.apache.org/maven2/io/github/pdvrieze/xmlutil/ // ktlint-disable max-line-length
43+
if ((project.name != "ktor-server-config-yaml") && (project.name != "ktor-serialization-kotlinx-xml")) {
44+
watchosDeviceArm64()
45+
} else {
46+
null
47+
},
4348
).map { it.name }
4449
}
4550

buildSrc/src/main/kotlin/TargetsConfig.kt

+16-9
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,8 @@ fun Project.configureTargets() {
3232
kotlin {
3333
if (hasJs) {
3434
js {
35-
nodejs()
36-
// we don't test `server` modules in a browser.
37-
// there are 2 explanations why:
38-
// * logical - we don't need server in browser
39-
// * technical - we don't have access to files, os, etc.
40-
// Also, because of the ` origin ` URL in a browser, special support in `test-host` need to be implemented
41-
if (!project.name.startsWith("ktor-server")) browser()
35+
if (project.targetIsEnabled("js.nodeJs")) nodejs()
36+
if (project.targetIsEnabled("js.browser")) browser()
4237
}
4338

4439
configureJs()
@@ -48,8 +43,7 @@ fun Project.configureTargets() {
4843
@OptIn(ExperimentalWasmDsl::class)
4944
wasmJs {
5045
nodejs()
51-
// we don't test `server` modules in a browser.
52-
if (!project.name.startsWith("ktor-server")) browser()
46+
if (project.targetIsEnabled("wasmJs.browser")) browser()
5347
}
5448

5549
configureWasm()
@@ -354,3 +348,16 @@ fun Project.configureTargets() {
354348
}
355349
}
356350
}
351+
352+
/**
353+
* By default, all targets are enabled. To disable specific target,
354+
* disable the corresponding flag in `gradle.properties` of the target project.
355+
*
356+
* Targets that could be disabled:
357+
* - `target.js.nodeJs`
358+
* - `target.js.browser`
359+
* - `target.wasmJs.browser`
360+
*/
361+
internal fun Project.targetIsEnabled(target: String): Boolean {
362+
return findProperty("target.$target") != "false"
363+
}

ktor-server/gradle.properties

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
#
4+
5+
# We don't test `server` modules in a browser.
6+
# there are 2 explanations why:
7+
# * logical - we don't need server in browser
8+
# * technical - we don't have access to files, os, etc.
9+
# Also, because of the ` origin ` URL in a browser, special support in `test-host` need to be implemented
10+
target.js.browser=false
11+
target.wasmJs.browser=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Klib ABI Dump
2+
// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, watchosArm32, watchosArm64, watchosSimulatorArm64, watchosX64]
3+
// Rendering settings:
4+
// - Signature version: 2
5+
// - Show manifest properties: true
6+
// - Show declarations: true
7+
8+
// Library unique name: <io.ktor:ktor-serialization-kotlinx-xml>
9+
final val io.ktor.serialization.kotlinx.xml/DefaultXml // io.ktor.serialization.kotlinx.xml/DefaultXml|{}DefaultXml[0]
10+
final fun <get-DefaultXml>(): nl.adaptivity.xmlutil.serialization/XML // io.ktor.serialization.kotlinx.xml/DefaultXml.<get-DefaultXml>|<get-DefaultXml>(){}[0]
11+
12+
final fun (io.ktor.serialization/Configuration).io.ktor.serialization.kotlinx.xml/xml(nl.adaptivity.xmlutil.serialization/XML = ..., io.ktor.http/ContentType = ...) // io.ktor.serialization.kotlinx.xml/xml|[email protected](nl.adaptivity.xmlutil.serialization.XML;io.ktor.http.ContentType){}[0]
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
/*
2-
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
plugins {
66
id("kotlinx-serialization")
77
}
88

99
kotlin.sourceSets {
10-
jvmMain {
10+
commonMain {
1111
dependencies {
1212
api(project(":ktor-shared:ktor-serialization:ktor-serialization-kotlinx"))
1313
api(libs.xmlutil.serialization)
1414
}
1515
}
16+
commonTest {
17+
dependencies {
18+
implementation(project(":ktor-shared:ktor-serialization:ktor-serialization-kotlinx:ktor-serialization-kotlinx-tests")) // ktlint-disable max-line-length
19+
}
20+
}
1621
jvmTest {
1722
dependencies {
18-
api(project(":ktor-client:ktor-client-tests"))
19-
api(project(":ktor-server:ktor-server-test-host"))
20-
api(project(":ktor-client:ktor-client-plugins:ktor-client-content-negotiation:ktor-client-content-negotiation-tests")) // ktlint-disable max-line-length
21-
api(project(":ktor-shared:ktor-serialization:ktor-serialization-kotlinx:ktor-serialization-kotlinx-tests"))
22-
23-
api(libs.logback.classic)
23+
implementation(project(":ktor-client:ktor-client-plugins:ktor-client-content-negotiation:ktor-client-content-negotiation-tests")) // ktlint-disable max-line-length
2424
}
2525
}
2626
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package io.ktor.serialization.kotlinx.xml
@@ -21,13 +21,11 @@ import nl.adaptivity.xmlutil.serialization.*
2121
*
2222
* See [XML] for more details.
2323
*/
24-
@OptIn(XmlUtilInternal::class)
2524
public val DefaultXml: XML = XML {
2625
repairNamespaces = true
2726
xmlDeclMode = XmlDeclMode.None
2827
indentString = ""
2928
autoPolymorphic = false
30-
this.xmlDeclMode
3129
}
3230

3331
/**

ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-xml/jvm/test/XmlSerializationTest.kt ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-xml/common/test/XmlSerializationTest.kt

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
import io.ktor.http.*
@@ -9,6 +9,7 @@ import io.ktor.serialization.kotlinx.*
99
import io.ktor.serialization.kotlinx.xml.*
1010
import io.ktor.test.dispatcher.*
1111
import io.ktor.util.reflect.*
12+
import io.ktor.utils.io.charsets.*
1213
import kotlinx.serialization.*
1314
import kotlin.test.*
1415

@@ -45,6 +46,14 @@ class XmlSerializationTest {
4546

4647
private suspend inline fun <reified T : Any> ContentConverter.testSerialize(data: T): String {
4748
val content = serialize(ContentType.Application.Xml, Charsets.UTF_8, typeInfo<T>(), data)
48-
return (content as? TextContent)?.text ?: error("Failed to get serialized $data")
49+
val xml = checkNotNull((content as? TextContent)?.text) { "Failed to get serialized $data" }
50+
return xml.normalizeXml()
4951
}
52+
53+
// Output of XML serializer differs on different targets, so we should normalize it before comparison.
54+
// See: https://github.com/pdvrieze/xmlutil/blob/v0.90.1/serialization/src/commonTest/kotlin/nl/adaptivity/xml/serialization/TestCommon.kt#L43-L46
55+
private fun String.normalizeXml(): String = replace(" />", "/>")
56+
.replace(" ?>", "?>")
57+
.replace("\r\n", "\n")
58+
.replace("&gt;", ">")
5059
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
#
4+
5+
# xmlutil uses DOM API under the hood so it doesn't support Node.js.
6+
# Issue: https://github.com/pdvrieze/xmlutil/issues/83
7+
target.js.nodeJs=false

ktor-shared/ktor-serialization/ktor-serialization-kotlinx/ktor-serialization-kotlinx-xml/jvm/test/XmlServerKotlinxSerializationTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*
2-
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
import io.ktor.http.*
66
import io.ktor.serialization.kotlinx.test.*
77
import io.ktor.serialization.kotlinx.xml.*
88
import io.ktor.server.plugins.contentnegotiation.*
9-
import java.nio.charset.*
9+
import io.ktor.utils.io.charsets.*
1010
import kotlin.test.*
1111

1212
class XmlServerKotlinxSerializationTest : AbstractServerSerializationKotlinxTest() {

0 commit comments

Comments
 (0)