question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Deserializing object declarations does not preserve identity

See original GitHub issue

When serializing and unserializing an object declaration, the resulting instance has a different identity than the original one, resulting in the objects being considered non-equal. For example:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.registerKotlinModule

fun main(vararg args: String) {
    val mapper = ObjectMapper().registerKotlinModule()

    val successPre = Success(42)
    val successJson = mapper.writeValueAsString(successPre)
    val successPost = mapper.readValue(successJson, Success::class.java)

    println(successPre == successPost) // Prints true

    val failurePre = Failure
    val json = mapper.writeValueAsString(failurePre)
    val failurePost = mapper.readValue(json, Failure::class.java)

    println(failurePre == failurePost) // Prints false
}

object Failure

data class Success(val foo: Int)

I would expect Jackson to return the one and only singleton instance that Kotlin created for the object and have behaviour similar to data classes.


You might wonder why I’d try to JSON serialize an object declaration. My use case is dealing with polymorphism having a sealed class with 2 implementation; one is a data class and the other is an object, like this:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
    JsonSubTypes.Type(value = Purpose.StockOnHand::class, name = "stockOnHand"),
    JsonSubTypes.Type(value = Purpose.Fulfillment::class, name = "fulfillment")
)
sealed class Purpose {
    object StockOnHand : Purpose()
    data class Fulfillment(val channel: String) : Purpose()
}

which translates to JSON like

{"type": "stockOnHand"}

or

{"type": "fulfillment", "channel": "foo"}

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
Gama11commented, Oct 1, 2020

It looks like this has actually been fixed in the meantime (see #225). Apparently there were some issues with it though (see #281) which led to it being an opt-in:

.registerModule(KotlinModule(singletonSupport = SingletonSupport.CANONICALIZE))
4reactions
MikeRipponcommented, Nov 8, 2018

I also have this problem.

@EdeMeijer I think provided you don’t mind having Jackson annotations in your code, this is a little cleaner/safer as it maintains the contract of there only ever being a single instance, rather than allowing Jackson to create multiple instances and hacking around equals.

sealed class Purpose {
    object StockOnHand : Purpose() {
        @JvmStatic @JsonCreator fun deserialize() = StockOnHand
    }
    data class Fulfillment(val channel: String) : Purpose()
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Does serialization preserve object identity? - Stack Overflow
The answer is no, by default object identity is not preserved via serialization if you are considering 2 separate serializations of a given ......
Read more >
Object serialization - R3 Documentation
You can use several workarounds to preserve the mutability of reconstituted objects. If the class is not a Kotlin data class, then it...
Read more >
How to Deserialize JSON Into Dynamic Object in C# - Code ...
Describe how to deserialize JSON into dynamic object in C# with detail explanation and examples using native and Newtonsoft library.
Read more >
12.10 Serializing Syntax - Racket Documentation
The preserve-property-keys lists syntax-property keys to whose values should be preserved in serialization, even if the property value was not added as ...
Read more >
XML Serialization
Unlike Binary Serialization, XML Serialization does not preserve type fidelity. In other words, it does not include type information. For example, if you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found