Kotlin中的Singleton序列化

时间:2017-06-07 11:46:35

标签: serialization singleton kotlin

我想知道在Kotlin中是否可以反序列化(恢复属性值)声明的对象,而无需手动分配属性或求助于反射。以下代码段进一步说明:

object Foo: Serializable {
    var propOne: String = ""
    // ...

    fun persist() {
        serialize(this) 
        // no problem with serialization
    }

    fun restore(bytes: ByteArray) {

        val fooObj: Foo = deserialize(bytes) as Foo
        // It seems Kotlin allows us to use singleton as type!

        // obvioulsly either of the following is wrong:
        // this = fooObj
        // Foo = fooObj

        // ... is there a way to 'recover' the singleton (object) other than 
        //     manual assignment of properties (or reflection) ???    
    }
}

2 个答案:

答案 0 :(得分:1)

无法使用新实例重新分配对单例的全局引用。最多可以在序列化期间写出属性,然后在反序列化时直接读取属性并改变原始对象中的状态。它需要自定义代码,您可以通过直接赋值或反射将属性分配到对象中。如果你创建自己的单例机制来保存一个可以换成另一个反序列化实例的实例会更好。

答案 1 :(得分:0)

遇到了相同的问题,并想与您分享我的解决方案:

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import java.io.File
import java.lang.reflect.Modifier

typealias ObjMap = HashMap<String, Any?>

fun <T : Any> T.getInstance() : Any? {
    val target = if(this is Class<*>) this else javaClass

    return target.getDeclaredField("INSTANCE")?.get(null)
}

class ObjectHelper {
    companion object {
        val mapper = ObjectMapper().apply {
            enable(SerializationFeature.INDENT_OUTPUT)
            configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        }

        fun objectToMap(obj: Any): ObjMap {
            var res = ObjMap()

            val instance = obj.getInstance()
            val o = instance ?: obj

            o.javaClass.declaredFields.forEach {
                if(it.name != "INSTANCE") {
                    it.isAccessible = true
                    val value = if(Modifier.isStatic(it.modifiers)) it.get(null) else it.get(o)
                    res[it.name] = value
                }
            }

            o.javaClass.classes.forEach {
                res[it.simpleName] = objectToMap(it)
            }

            return res
        }

        fun saveObject(path: String, obj: Any)  {
            mapper.writeValue(File(path), objectToMap(obj))
        }

        fun loadObject(path: String, obj: Any) {
            val json = mapper.readValue<HashMap<*,*>>(File(path), HashMap::class.java) as ObjMap

            loadObject(obj, json)
        }

         fun loadObject(obj: Any, props: ObjMap) {
            val objectParam = mapper.writeValueAsString(props)

            mapper.readValue(objectParam, obj::class.java)

            obj.javaClass.classes.forEach {
                val instance = it.getInstance()
                val map = props[it.simpleName]

                if(map != null && instance != null) {
                    loadObject(instance, map as ObjMap)
                }
            }
        }
    }
}

用法示例:

 object TestObj {
        var f1: String = "f1"
        var f2: String = "f2"

        object TestObj_2 {
            var f1: String = "f1_1"
            var f2: String = "f2_2"
        }
    }

        TestObj.f1 = "aaa"
        saveObject("out.json", TestObj)

        TestObj.f1 = "bbb"
        loadObject("out.json", TestObj)

        println(TestObj.f1)

结果将为“ aaa”。