Skip to content

Deserializing singleton object causes different instances #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ingramchen opened this issue Mar 21, 2018 · 4 comments
Closed

Deserializing singleton object causes different instances #141

ingramchen opened this issue Mar 21, 2018 · 4 comments

Comments

@ingramchen
Copy link

Step to reproduce:

object Singleton

val mapper = ObjectMapper().registerModule(KotlinModule())
val decoded = mapper.readValue("{}", Singleton::class.java)
assert(Singleton == decoded)  // failed

Expect behavior: object declaration should be only one instance per VM

Environment:
Oracle JDK 1.8 (also reproduce in Android)
Kotlin 1.2.30
Jackson, Jackson kotlin - 2.9.4

@apatrida
Copy link
Member

apatrida commented Apr 3, 2018

This is outside the scope of the module, you cannot replace an object singleton in Kotlin, and if it is immutable values the content could not be set. Jackson does not "bind into existing instances" for any case and the definition of readValue is specifically to create new objects created from the contents of the JSON. The Kotlin module only provides information to the data binder and does not control when it decides to create an instance only in how it knows how to create that instance.

@apatrida apatrida closed this as completed Apr 3, 2018
@cowtowncoder
Copy link
Member

The only addition I have is that Jackson 2.9 does actually allow "merging", in which case existing Object instance will be modified. This is controlled by one of:

  1. Annotation on property (@JsonMerge), introspected using AnnotationIntrospector.findMergeInfo()
  2. Config overrides: per-type, or, global default

That said, I don't know if that could be relevant here; the root value is trickier, as intent is that caller would use updateValue() instead of readValue().

Specifically I don't know if Kotlin has enough metadata to let runtime understand that given class only exists for singleton usage. If not, there's not much that can be done automatically.

@williamboxhall
Copy link

I don't really understand the problem here, you can detect if a class corresponds to a singleton object by checking it's constructors, then calling .objectInstance on it. In fact you can simply use the presence of objectInstance to tell if it's a singleton object:

$ kotlinc-jvm
Welcome to Kotlin version 1.3.41 (JRE 11.0.7+10-LTS)
Type :help for help, :quit for quit
>>> object Foo
>>> data class Bar(val baz: String)
>>> class Quux()
>>> val fooClass = Foo::class
>>> val barClass = Bar::class
>>> val quuxClass = Quux::class
>>> println(listOf(fooClass, barClass, quuxClass).map { it.simpleName to it.constructors })
[(Foo, []), (Bar, [fun <init>(kotlin.String): Line_1.Bar]), (Quux, [fun <init>(): Line_2.Quux])]
>>> fooClass.objectInstance
res8: Line_0.Foo? = Line_0$Foo@5788722f
>>> barClass.objectInstance
res9: Line_1.Bar? = null
>>> quuxClass.objectInstance
res10: Line_2.Quux? = null
>>>

@williamboxhall
Copy link

Sorry for the noise, this actually ended up getting fixed in #244

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants