创可贴网站怎么做图片大全,江都住房和建设局网站,企业线上培训课程,丹阳网站建设方案替代Gson、fastJson等传统java的json解析工具。抛弃传统的反射类解析字段#xff0c;利用kotlin的inlinereified特性和android可以预编译的特点#xff0c;在编译阶段的时候#xff0c;还原最后的类型#xff0c;来实现的json序列化与反序列化。
性能效率#xff1a;不做评…替代Gson、fastJson等传统java的json解析工具。抛弃传统的反射类解析字段利用kotlin的inlinereified特性和android可以预编译的特点在编译阶段的时候还原最后的类型来实现的json序列化与反序列化。性能效率不做评价2025年了手机性能的提升和移动场景的数据量json工具之间的时间消耗并非我们取舍的关键点。日常使用难度与gson相比最重要是需要更多标注类的注解序列化和反序列化相对简单优点不用加混淆规则。集成// 根目录 build.gradle.ktsplugins{kotlin(multiplatform)version2.2.0// 如果需要多平台支持kotlin(jvm)version1.9.10// 如果是 JVM 项目}// 直接声明依赖版本val kotlinxSerializationJsonVersion1.9.0val kotlinReflectVersion1.9.10// 添加插件plugins{id(org.jetbrains.kotlin.plugin.serialization)version1.9.10}// 模块目录 build.gradle.ktsplugins{kotlin(jvm)// 或 kotlin(multiplatform) 如果是多平台项目id(org.jetbrains.kotlin.plugin.serialization)version1.9.10}dependencies{implementation(org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationJsonVersion)implementation(org.jetbrains.kotlin:kotlin-reflect:$kotlinReflectVersion)}基本使用定义全局单例附带常用参数//单例objectGlobals{ksonJson{ignoreUnknownKeystrue// 后端多给字段也不报错encodeDefaultstrue// 输出默认值关掉可减小体积prettyPrintfalse// 日常关调试可开isLenienttrue// 宽松模式允许非标准 JSONexplicitNullsfalse// null 字段不主动输出//allowTrailingComma true// classDiscriminator type // 多态时的类型标记字段名见下// namingStrategy JsonNamingStrategy.SnakeCase // 字段命名转换版本要求较新}}定义Bean类importkotlinx.serialization.SerialNameimportkotlinx.serialization.Serializableimportkotlinx.serialization.TransientSerializableclassUser{varname:Stringvarage:Int0varemail:String?null//空安全varisActive:BooleantrueSerializedName(created_at)varcreatedAt:String,valsex:Stringmale,//默认值}valuserUser(Alice,30,aliceexample.com)// 序列化valjsonStringJson.encodeToString(user)// 反序列化valuserFromJsonJson.decodeFromStringUser(jsonString)// 输出: {name:Alice,age:30,email:aliceexample.com,isActive:true,created_at:...}常用注解Serializable类名必须标记。否则运行报错。后续封装Util的泛型传入也必须是注解的类。SerialName作用JSON key映射不论序列化或者反序列化都会改成注解后的字段。JsonNames// 用于为同一字段提供多个可能的JSON键名SerializabledataclassUser(JsonNames(user_name,username,userName)valname:String,JsonNames(user_email,email_address)valemail:String?null)// 使用示例valjson1{user_name: Alice, user_email: alicetest.com}valjson2{username: Bob, email_address: bobtest.com}kson.decodeFromStringUser(json1)✅...valbean1User(Alice,alicetest.com)kson.encodeToString(bean1)//得到 {name:Alice, email: alicetest.com}能够识别任意JsonNames从json字符串反序列化为对象序列化还是转成现有字段并且SerialName优先级更高。Transient忽略字段。注意是kotlinx.serialization.Transient。不论序列化或者反序列化都当做不存在一样。Contextual 进阶自定义解析器章节。特性可空字段 其中定义了email:String?字段就是空安全允许jsonString不存在该内容反序列化后的对象该变量就是null默认值sex male, 如果jsonString不存在该内容反序列化后的对象该变量就是male。需要给json{}添加参数json{//...encodeDefaultstrue}泛型API我们一般遇到的是这种caseSerializablesealedclassBaseBean{abstractvalcode:Stringabstractvalmessage:String?abstractvalstatus:Boolean}SerializableSerialName(result)dataclassResultBeanT(overridevalcode:String,overridevalmessage:String?,overridevalstatus:Boolean,valdata:T?null):BaseBean()直接使用只要你的嵌套data的Class使用注解即可。类似org.json.JSONObject的使用//org.json.JSONObjectvarjsonObjectJSONObject(result)valcodejsonObject.optString(code)//Kson使用方式valelementJson.parseToJsonElement({age:18,data:[x,y]})println(element.jsonObject[age]?.jsonPrimitive?.int)// 18valelementJsonParser.parseString({age:18,data:[x,y]})println(element.asJsonObject[age].asInt)// 18valobjbuildJsonObject{put(name,Xiao ming)put(classes,buildJsonArray{add(Math)add(Chinese)})}配合Retrofit、KtorobjectNetworkClient{privatevaljsonJson{ignoreUnknownKeystrueisLenienttrue}valinstance:Retrofitbylazy{Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(json.asConverterFactory(application/json.toMediaType())).build()}}valclientHttpClient(OkHttp){install(ContentNegotiation){json(Json{ignoreUnknownKeystrue// classDiscriminator type})}}进阶使用自定义解析器必须掌握对于某些字段我们需要自定义非普通类型又无法自定义Class比如系统的Cookie类UUID类Color类等必须自定义解析器后注解Serializable(with xxx::class)标记。方法一先编写KSerializerXXX转换器比如UUIDAsString。然后给需要转化的字段使用Serializable(withUUIDAsString::class)objectUUIDAsString:KSerializerUUID{overridevaldescriptor:SerialDescriptorPrimitiveSerialDescriptor(UUIDAsString,PrimitiveKind.STRING)overridefunserialize(encoder:Encoder,value:UUID){encoder.encodeString(value.toString())}overridefundeserialize(decoder:Decoder):UUIDUUID.fromString(decoder.decodeString())}SerializabledataclassWithUuid(Serializable(withUUIDAsString::class)//方法一valid:UUID)SerializabledataclassWithUuid(Contextual//方法二valid:UUID)valmoduleSerializersModule{contextual(UriSerializer)}valjsonJson{serializersModulemodule}方法二先编写KSerializerXXX转换器如上。然后将它在Json{}申明的时候注册字段使用Contextual注解标注。sealed class功能强大后补学习SerializablesealedclassMessage{SerializableSerialName(text)dataclassText(valcontent:String,valsender:String):Message()SerializableSerialName(image)dataclassImage(valurl:String,valwidth:Int,valheight:Int):Message()SerializableSerialName(video)dataclassVideo(valurl:String,valduration:Int,valthumbnail:String):Message()}// 测试代码funtestSealedClass(){valjsonJson{classDiscriminatortype// 指定类型标识字段名prettyPrinttrue}// 创建不同子类的实例valmessageslistOf(Message.Text(Hello World,Alice),Message.Image(https://example.com/img.jpg,800,600),Message.Video(https://example.com/video.mp4,120,thumb.jpg))// 序列化messages.forEach{msg-valjsonStrjson.encodeToString(msg)println(序列化结果:\n$jsonStr)// 反序列化valdecodedjson.decodeFromStringMessage(jsonStr)println(反序列化结果:$decoded\n)}// 测试JSON示例valjsonText{type:text,content:Hi there,sender:Bob}valjsonImage{type:image,url:test.png,width:100,height:100}valtextMsgjson.decodeFromStringMessage(jsonText)valimageMsgjson.decodeFromStringMessage(jsonImage)// 使用when处理不同类型when(textMsg){isMessage.Text-println(收到文本消息:${textMsg.content})isMessage.Image-println(收到图片:${textMsg.url})isMessage.Video-println(收到视频:${textMsg.url})}}序列化结果: { type: text, content: Hello World, sender: Alice } 反序列化结果: Text(contentHello World, senderAlice) 序列化结果: { type: image, url: https://example.com/img.jpg, width: 800, height: 600 } 反序列化结果: Image(urlhttps://example.com/img.jpg, width800, height600)如果你们后端采用的是这样平铺在type同级的字段方式。可以采用sealed class的做法。如果你们是通过这下设计的嵌套字段SerializabledataclassMediaResultBeanT(valtype:String,valdata:T?null)SerializabledataclassImage(valurl:String,valwidth:Int,valheight:Int)SerializabledataclassVideo(valurl:String,valduration:Int,valthumbnail:String)无需特殊处理。开放层级 多态SerializersModule 和 polymorphic完全可跳过完全可以跳过你可以不需要这种设计方案。importkotlinx.serialization.*// 开放多态基类不是sealed class或不是SerializableopenclassMsg(valid:String)SerializableSerialName(text)dataclassTextMsg(valcontent:String,overridevalid:String// 必须覆盖基类属性):Msg(id)SerializableSerialName(image)dataclassImageMsg(valurl:String,valsize:Int,overridevalid:String):Msg(id)// 创建序列化模块valmessageModuleSerializersModule{// 注册多态类型polymorphic(Msg::class){// 为每个子类指定序列化器和类型名subclass(TextMsg::class,TextMsg.serializer())subclass(ImageMsg::class,ImageMsg.serializer())// 可以动态添加更多子类}// 可以同时注册多个多态基类polymorphic(Any::class){// 为Any类型注册序列化器subclass(String::class,serializer())subclass(Int::class,serializer())}}// 使用模块创建Json实例valjsonWithModuleJson{serializersModulemessageModule classDiscriminatormsg_type// 类型标识字段名ignoreUnknownKeystrue}// 测试用例funtestPolymorphic(){valmessages:ListMsglistOf(TextMsg(Hello,1),ImageMsg(pic.jpg,1024,2))// 序列化messages.forEach{msg-valjsonjsonWithModule.encodeToString(PolymorphicSerializer(Msg::class),// 必须使用多态序列化器msg)println(序列化:$json)// 反序列化valdecodedjsonWithModule.decodeFromStringMsg(json)println(反序列化:${decoded::class.simpleName})}// JSON格式示例valjsonStr [ {msg_type:text,id:1,content:Hello}, {msg_type:image,id:2,url:pic.jpg,size:1024} ] .trimIndent()vallistSerializerListSerializer(PolymorphicSerializer(Msg::class))valdecodedListjsonWithModule.decodeFromString(listSerializer,jsonStr)}// 动态添加子类运行时注册fundynamicRegistration(){// 创建可变的模块valmutableModuleSerializersModule{}// 运行时动态添加SerializableSerialName(audio)dataclassAudioMsg(valurl:String,valduration:Int,valid:String):Msg(id)// 注意动态添加比较麻烦通常建议在模块构建时就注册所有类型}封装使用AI做了测试25条用例做了覆盖日常开发常用13种class定义方式涵盖泛型嵌套泛型ListMap嵌套List等超过60条各类测试条目。最终整合出一个日常通用的Util类做各类解析//单例objectGlobals{ksonJson{ignoreUnknownKeystrue// 后端多给字段也不报错encodeDefaultstrue// 输出默认值关掉可减小体积prettyPrintfalse// 日常关调试可开isLenienttrue// 宽松模式允许非标准 JSONexplicitNullsfalse// null 字段不主动输出//allowTrailingComma true// classDiscriminator type // 多态时的类型标记字段名见下// namingStrategy JsonNamingStrategy.SnakeCase // 字段命名转换版本要求较新}}/** * 专攻ListAny, MapString, Any?的toString。 */Deprecated(极度受限使用上位版本[toKsonString])funAny.toKsonStringLimited():StringGlobals.kson.encodeToString(this.toKsonElementLimited())Deprecated(极度受限使用上位版本[toKsonString])internalfunAny?.toKsonElementLimited():JsonElementwhen(this){null-JsonNullisJsonElement-thisisNumber-JsonPrimitive(this)isBoolean-JsonPrimitive(this)isString-JsonPrimitive(this)isArray*-JsonArray(map{it.toKsonElementLimited()})isList*-JsonArray(map{it.toKsonElementLimited()})isMap*,*-JsonObject(map{it.key.toString()toit.value.toKsonElementLimited()}.toMap())//经过测试其实这里也是要求this这个class必须是使用 Serializable注解的。因此尽量使用toJsonStringTyped//同时对于嵌套泛型的解析这是无法支持的。因为这里仅是拿了第一层。else-Globals.kson.encodeToJsonElement(serializer(this::class.createType()),this)}inlinefunreifiedTT.toKsonString():StringGlobals.kson.encodeToString(this)inlinefunreifiedTString.fromKson()ignoreError{Globals.kson.decodeFromStringT(this)}inlinefunT:AnyignoreError(block:()-T?):T?{returntry{block.invoke()}catch(e:Throwable){e.printStackTrace()null}}整个测试下来我们只需要如上3个函数就能覆盖99%的工作因为全部kson库toString和fromString要求的都是inlinereified因为一般情况我们不需要传入解析器。所以toKsonString(): 用来序列化成字符串fromKson(): 用来反序列化成T对象已经做了try-catchtoKsonStringLimited():只用来将MapString, Any ListAny转成String这适用于给后端传参的场景。混淆 / 体积一般不需要额外 keep因编译期生成并显式引用。如果你自定义了 KSerializer 或用了反射式工厂才可能需要补充 keep。体积优化关闭 prettyPrint必要时 explicitNullsfalse并按需关闭 encodeDefaults。常见坑与排查忘记加插件id(“org.jetbrains.kotlin.plugin.serialization”)。字段名对不上用 SerialName 或开 namingStrategy。接口偶发多字段ignoreUnknownKeys true。后端大小写不一致JsonNamingStrategy.SnakeCase 或 JsonNames(…) 做兼容。多态无法解析确认 classDiscriminator 字段名与后端一致开放多态要注册 SerializersModule。时间类型优先 kotlinx-datetime或写自定义 KSerializer。