Kotlin Json 序列化1 - 基本功能实现

参考:

  • https://github.com/yole/jkid
  • Kotlin 反射;
  • Kotlin 注解;
  • Koltin 泛型;
  • Json 序列化是将一个对象,转换成Json形式的字符串;反序列化是将json格式字符串转成相应的对象;

    1. 分析

    如下:代码

    // 数据类
    data class Person(val name: String, val age: Int, val likes: List<String>)
    // 测试代码
    val p = Person("better", 30, listOf("Java", "Kotlin", "Python"))
    println(serialize(p)) 
    
    {"age": 30, "likes": ["Java", "Kotlin", "Python"], "name": "better"}
    

    将类的每个属性作为 json 的 key,value 为 key 对象的值,如果value 为 List 形式,即对应json的数组形式[];

    我们可通过反射获取类的所有属性,然后遍历,分别将每个属性,映射成json对应的 key 、value;

    2. kotlin 代码实现

    会有大量字符串拼接,所以为StringBuilder添加扩展函数来整体拼接

    整体步骤:

  • 获取类的所有KProperty;
  • 遍历 KProperty 集合,获取每个 KProperty
  • 每个KProperty都有他的名字与值,对应json的 key,value,value 处理时,需进行类型判断;
  • // 对外全局方法
    fun serialize(obj: Any) = buildString { serializeObj(obj) }
    private inline fun StringBuilder.serializeObj(o: Any) {
        // ==== 1. 获取类的所有`KProperty`
        o.javaClass.kotlin.memberProperties.joinToStringBuilder(this, separator = ",", prefix = "{", postfix = "}") {
            // ==== 2.遍历 `KProperty` 集合,获取每个 `KProperty`,进行类型判断,并处理;
            serializeProperty(it, o)
    private inline fun StringBuilder.serializeProperty(property: KProperty1<Any, *>, receiver: Any) {
        // ====3. 每个`KProperty`都有他的名字与值,对应json的 key,value,value 处理时,需进行类型判断;
        val key = property.name
        // 处理key
        serializeString(key)
        append(": ")
        // 处理value
        val value = property.get(receiver)
        serializePropertyValue(value)
    // 处理属性值
    private fun StringBuilder.serializePropertyValue(value: Any?) {
        when (value) {
            null -> append("null")
            is String -> serializeString(value)
            is Boolean, is Number -> append(value.toString())
            is List<*> -> serializeList(value)
            else -> serializeObj(value)
     * 处理list
    private fun StringBuilder.serializeList(data: List<Any?>) {
        data.joinToStringBuilder(this,  separator = ", " ,prefix = "[", postfix = "]") {
            serializePropertyValue(it)
    // 属性名称
    private inline fun StringBuilder.serializeString(name: String) {
        // like "better"
        append('\"').append("$name").append('\"')
    // 这里对joinToString 进行了改写,使其支持 ((T) -> Unit)
    fun <T> Iterable<T>.joinToStringBuilder(sb: StringBuilder, separator: CharSequence = ", ",
                                            prefix: CharSequence = "",
                                            postfix: CharSequence = "",
                                            limit: Int = -1,
                                            truncated: CharSequence = "...",
                                            transform: ((T) -> Unit)? = null): StringBuilder {
        return joinTo(sb, separator, prefix, postfix, limit, truncated) {
            if (transform == null) {    // 包装器模式
                return@joinTo it.toString()
            transform.invoke(it)
    

    3. 测试1 :

    // 数据类
    data class Person(val name: String, val age: Int, val likes: List<String>)
    // 测试代码
    val p = Person("better", 30, listOf("Java", "Kotlin", "Python"))
    println(serialize(p))  // 没问题
    

    4. 测试2 ,新增类

    data class County(val name: String, val peopleCount: Int) data class City(val name: String, val counties: List<County>) data class Province(val name: String, val size: Int, val cities: List<City>?) val c1 = County("湘潭县", 20_000) val c2 = County("株洲县", 30_000) val c4 = County("攸县", 40_000) val ci1 = City("湘潭市", listOf(c1)) val ci2 = City("株洲市", listOf(c2, c4)) val p1 = Province("湖南省", 780, listOf(ci1, ci2)) println(serialize(p1))

    格式化为:

    "cities": [{ "counties": [{ "name": "湘潭县", "peopleCount": 20000 "name": "湘潭市" "counties": [{ "name": "株洲县", "peopleCount": 30000 "name": "攸县", "peopleCount": 40000 "name": "株洲市"