假设有一个 interface 和 2 个(或更多)实现:
interface IRunnable {
fun run()
}
class Horse : IRunnable {
override fun run() { println("horse running") }
}
class Dog : IRunnable {
override fun run() { println("dog running") }
}
Run Code Online (Sandbox Code Playgroud)
想实现网络传输最简洁的JSON,即{"runnable":"H"}for Horse和{"runnable":"D"}for Dog
如果我不能修改接口和实现,我想将接口/实现序列化为 JSON,根据 Kotlin 的文档,我必须编写一个 自定义序列化器,并使用它SerializersModule来实现目标。
假设只有Horse和Dog实现IRunnable,这就是我所做的:
class RunnableSerializer : KSerializer<IRunnable> {
override val descriptor: SerialDescriptor
get() = StringDescriptor.withName("runnable")
override fun serialize(encoder: Encoder, obj: IRunnable) {
val …Run Code Online (Sandbox Code Playgroud) 我正在尝试将 JSON 文件反序列化为我无法使用kotlinx.serialization.
该类看起来类似于:
public data class Lesson(
val uid: String,
val start: Instant,
val end: Instant,
val module: String,
val lecturers: List<String>,
val room: String?,
val type: String?,
val note: String?
)
Run Code Online (Sandbox Code Playgroud)
我尝试解析的 JSON 如下所示:
{
"lessons": [
{
"uid": "sked.de956040",
"start": "2020-11-02T13:30:00Z",
"end": "2020-11-02T16:45:00Z",
"module": "IT2101-Labor SWE I: Gruppe 1 + 2",
"lecturers": [
"Kretzmer"
],
"room": "-",
"type": "La",
"note": "Prüfung Online"
}
]
}
Run Code Online (Sandbox Code Playgroud)
这是通过以下方式尝试的:
@Serializable
data class ExpectedLessons(
val lessons: List<Lesson>
)
val …Run Code Online (Sandbox Code Playgroud) 我一直在玩 Kotlinx.serialisation。我一直在尝试找到一种使用 Kotlinx.serialisation 的快速方法来创建一个简单的 JSON(主要是将其发送出去),并且代码混乱。
对于一个简单的字符串,例如:
{"Album": "Foxtrot", "Year": 1972}
Run Code Online (Sandbox Code Playgroud)
我一直在做的是这样的:
val str:String = Json.stringify(mapOf(
"Album" to JsonPrimitive("Foxtrot"),
"Year" to JsonPrimitive(1972)))
Run Code Online (Sandbox Code Playgroud)
这远不是很好。我的元素大多是原始的,所以我希望我有这样的东西:
val str:String = Json.stringify(mapOf(
"Album" to "Sergeant Pepper",
"Year" to 1967))
Run Code Online (Sandbox Code Playgroud)
此外,我很高兴有一个带有嵌套 JSON 的解决方案。就像是:
Json.stringify(JsonObject("Movies", JsonArray(
JsonObject("Name" to "Johnny English 3", "Rate" to 8),
JsonObject("Name" to "Grease", "Rate" to 1))))
Run Code Online (Sandbox Code Playgroud)
那会产生:
{
"Movies": [
{
"Name":"Johnny English 3",
"Rate":8
},
{
"Name":"Grease",
"Rate":1
}
]
}
Run Code Online (Sandbox Code Playgroud)
(不一定美化,甚至更好)
有这样的吗?
注意:使用序列化器很重要,而不是直接的字符串,例如
"""{"Name":$name, "Val": $year}"""
Run Code Online (Sandbox Code Playgroud)
因为连接字符串是不安全的。任何非法字符都可能会破坏 JSON!我不想处理转义非法字符:-(
谢谢
webSocket("/ws") {
try {
while (true) {
when(val frame = incoming.receive()){
is Frame.Text -> {
val text = frame.readText() //i want to Serialize it to class object
send(Frame.Text(processRequest(text)))
}
else -> TODO()
}
}
} finally {
TODO()
}
}
Run Code Online (Sandbox Code Playgroud)
我想序列化frame.readText()以返回类对象我对 Ktor 世界完全陌生,我不知道这是否可能
我有一个为网络流量序列化的类。
@Serializable
data class Packet(val dataType: String, val payload: Any)
Run Code Online (Sandbox Code Playgroud)
我已经使用 Java 序列化通过网络发送它。接收器无法知道有效负载的类型,但 Java 反序列化它就好了,然后我when(dataType)用作查找以将Any对象正确地转换为正确的类型。轻松活泼。
但是 Kotlinx Serialization(带有 ProtoBuf)是这种Any类型的坚持者,原因对我来说并不明显。我无法为Any. 在文档中,他们推荐了一种多态方法,这可以正常工作,但您必须输入数据包:
data class Packet<out T : Any>(val dataType: String, val payload: T) : SomeBaseClass<T>
Run Code Online (Sandbox Code Playgroud)
但这有点糟糕,因为它使用内联具体化类型压低了许多代码路径,而且这并不能解决接收端不知道尝试反序列化有效负载的类型而无需先查看dataType字段的问题。
这是最糟糕的 catch-22。该框架不会忽略该payload: Any字段(给出编译错误),我什至无法编写自定义序列化程序,因为在客户序列化程序中定义element类型Any(用于描述符)会产生相同的运行时错误“未注册序列化程序”为Any。”
对于以下 Proguard 规则(以Kotlin 序列化为例)
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
Run Code Online (Sandbox Code Playgroud)
-if在上述规则的上下文中,的含义是什么?我尝试查看官方 proguard 文档,但找不到任何相关信息
我有一个 kotlin 类和一个对象
@Serializable
@SerialName("Cl")
class Cl(...)
@Serializable
@SerialName("Obj")
object Obj
Run Code Online (Sandbox Code Playgroud)
我的混淆器配置如下
-keepclassmembers class kotlinx.serialization.json.** {
*** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
kotlinx.serialization.KSerializer serializer(...);
}
-keepclasseswithmembers class .** {
kotlinx.serialization.KSerializer serializer(...);
}
-keep,includedescriptorclasses class my.package.**$$serializer { *; }
Run Code Online (Sandbox Code Playgroud)
但是,虽然保留了类的序列化程序,但对象的序列化程序却没有保留。这是类的映射:
Cl -> Cl:
...
...
67:67:void <init>(... ,kotlinx.serialization.internal.SerializationConstructorMarker) -> <init>
70:75:void <init>(...) -> <init>
67:67:void write$Self(Cl,kotlinx.serialization.encoding.CompositeEncoder,kotlinx.serialization.descriptors.SerialDescriptor) -> e
Cl$$serializer -> Cl$$serializer:
...
67:75:void <clinit>() -> <clinit>
67:67:void <init>() -> <init>
67:67:kotlinx.serialization.KSerializer[] childSerializers() -> childSerializers
67:67:Cl deserialize(kotlinx.serialization.encoding.Decoder) -> deserialize
67:67:java.lang.Object deserialize(kotlinx.serialization.encoding.Decoder) …Run Code Online (Sandbox Code Playgroud) 我使用kotlinx.serialization库来序列化/反序列化 JSON。有一个 JSON 字符串:
{"id":"1"}
Run Code Online (Sandbox Code Playgroud)
也可以表示为
{"uid":"1"}
Run Code Online (Sandbox Code Playgroud)
我想用一个属性处理两个名字,例如:
@Serializable
data class User(val id: String)
Run Code Online (Sandbox Code Playgroud)
是否可以仅使用一个data类及其属性来解析两个 JSON?
serialization json kotlin json-deserialization kotlinx.serialization
使用Jackson进行序列化,有@JsonRawValue注解实现字符串值不带引号序列化。例如,使用以下代码
data class SomeData {
@JsonRawValue
value: String
}
Run Code Online (Sandbox Code Playgroud)
我可以序列化SomeData("{}")并获取:
{ "value": {} }
Run Code Online (Sandbox Code Playgroud)
(如果没有注释,那就是{ "value": "{}" }。)
我想使用 Kotlin 序列化来实现相同的目的。
我想要这个的原因是我通过 Rest 获取一个对象,将其存储在数据库中,稍后从那里加载它并返回它而不更改内容。我不关心对象中包含什么。所以我绝对不需要以任何方式解析或反序列化它。在最坏的情况下,内容会在过程中的某个地方被更改。在最好的情况下,这只是一些多余的计算。
kotlinx-serialization 中似乎没有相应的机制支持这种开箱即用的操作。查看源代码,似乎我需要一个带有 a 的类JsonPrimitive(或JsonLiteral)实例String value,但isString设置为 false,但没有办法得到它。
另一种方法可能是编写一个序列化器来序列化String不带引号的值,但我不知道如何实现。
我想创建一个大致如下所示的类:
class MyWrapperClass<T: IsSerializable>(val someData: T) {
fun stringifyMe(): String {
return Json.encodeToString(someData)
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是关于那种IsSerializable类型的。我只想接受已标记为 的类型@Serializable,以便我可以调用Json.encodeToString()它们。这可能吗?
我尝试了如上所述的代码,但收到错误“无法使用 'T' 作为具体化类型参数。请改用类。”。