美文网首页
Kotlin Json 序列化1 - 基本功能实现

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

作者: zhaoyubetter | 来源:发表于2018-02-07 23:56 被阅读975次

    参考:

    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添加扩展函数来整体拼接

    整体步骤:

    1. 获取类的所有KProperty;
    2. 遍历 KProperty 集合,获取每个 KProperty
    3. 每个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": "株洲市"
        }],
        "name": "湖南省",
        "size": 780
    }
    

    相关文章

      网友评论

          本文标题:Kotlin Json 序列化1 - 基本功能实现

          本文链接:https://www.haomeiwen.com/subject/sutzzxtx.html