Serialization Kotlin中的单例序列化

Serialization Kotlin中的单例序列化,serialization,singleton,kotlin,Serialization,Singleton,Kotlin,我想知道在Kotlin中是否可以对声明对象进行反序列化(还原属性值),而不必手动分配属性或诉诸反射。下面的代码片段进一步解释: object Foo: Serializable { var propOne: String = "" // ... fun persist() { serialize(this) // no problem with serialization } fun restore(bytes: By

我想知道在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) ???    
    }
}

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

遇到同样的问题,希望与您分享我的解决方案:

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)
                }
            }
        }
    }
}

结果将是“aaa”

你确定你不想在这里上普通课吗?带有变量的单例基本上是全局可变状态。@marstran:setter可以设置为
私有
内部
。它仍然是全局可变状态。它可以被全球访问,也可以变异。是的,两者都可能非常糟糕。
 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)