can not serialize data class in data class with objectmapper and kotlin - kotlin

Can not serialize data class in data class with kotlin and objectmapper
I'am using kotlin version "1.3.72" and
com.fasterxml.jackson.module:jackson-module-kotlin version "2.11.2".
This is my classes
data class A(val b: B)
data class B(val name: String)
val a = A(B(name = "name")
objectMapper.writeValueAsString(a) // << failed!!!
Why couldn't serialize?

Related

can I use kotlinx serializer with multiple sealed class levels as parents and a nested invocation?

I am trying to use kotlinx #Serializable and Ive faced this issue:
I have the following classes:
#Serializable
sealed class GrandParent
a second one:
#Serializable
sealed class Parent() : GrandParent() {
abstract val id: String
}
and a third one
#Serializable
data class Child(
override val id: String, ....
): Parent()
I'm needing of grandparent since I use it as a generic type in another class, which happen to also have a reference to the GrandParent class
#Serializable
data class MyContent(
override val id: String,
....
val data: GrandParent, <- so it has a self reference to hold nested levels
...): Parent()
Every time I try to run this I get an error...
Class 'MyContent' is not registered for polymorphic serialization in the scope of 'GrandParent'.
Mark the base class as 'sealed' or register the serializer explicitly.
I am using ktor as wrapper, kotlin 1.5.10. I did this based on https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#registered-subclasses
Any ideas?
You should serialize and deserialize using your sealed class in order for kotlin serialization to "know" to add a discriminator with the right implementation. By default it search for type in the json but you can change it with JsonBuilder:
Json {
classDiscriminator = "class"
}
Here is an example:
#Serializable
sealed class GrandParent
#Serializable
sealed class Parent : GrandParent() {
abstract val id: String,
}
#Serializable
data class Child(
override val id: String,
): Parent()
#Serializable
data class MyContent(
override val id: String,
val data: GrandParent,
): Parent()
fun main() {
val test = MyContent(id = "test", data = Child(id = "child"))
val jsonStr = Json.encodeToString(GrandParent.serializer(), test)
println("Json string: $jsonStr")
val decoded = Json.decodeFromString(GrandParent.serializer(), jsonStr)
println("Decoded object: $decoded")
}
Result in console:
Json string: {"type":"MyContent","id":"test","data":{"type":"Child","id":"child"}}
Decoded object: MyContent(id=test, data=Child(id=child))
encode and decode can also be written like this (but behind the scenes it will use reflections):
val jsonStr = Json.encodeToString<GrandParent>(test)
println("Json string: $jsonStr")
val decoded = Json.decodeFromString<GrandParent>(jsonStr)
println("Decoded object: $decoded")

How to serialize kotlin sealed class with open val using kotlinx serialization

import kotlinx.serialization.Serializable
#Serializable
sealed class Exercise(open val id: String) {
#Serializable
data class Theory(override val id: String) : Exercise(id)
}
I have such kind of sealed class in my code, and compiler says me:
Serializable class has duplicate serial name of property 'id', either in the class itself or its supertypes.
Is there way to have open val in serializable sealed class, which works correctly when overriding it?
This is Kotlin issue KT-38958. It seems to be a corner case of the Constructor properties requirement.
It can be solved by using the following implementation,
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
#Serializable
sealed class Exercise {
abstract val id: String
#Serializable
data class Theory(override val id: String) : Exercise()
}
fun main() {
val t1 = Exercise.Theory("t1")
val t1Json = Json.encodeToString(t1)
println(t1Json)
println(Json.decodeFromString<Exercise.Theory>(t1Json).toString())
}
which will output:
{"id":"t1"}
Theory(id=t1)
For details, see "Designing serializable hierarchy" in the Kotlin Serialization Guide.

Wrapping data classes in kotlin

I wanted to ask about data classes in kotlin.
Suppose I have 2 data classes , data class A and data class B , I want to wrap my data class A around data class B.
Is this a case of Inheritance or inline class , I am kind of new to Kotlin .
data class A(
var x1:Float?,
var y1:Float?
)
data class B(
var x:Float?,
var y:Float?,
// other variables and methods
)
Thanks
You can't inherit a Kotlin data class from an other data class, but you can use interfaces or abstract classes and your data classes can implement/extend these:
abstract class A {
abstract var valueA: Int
}
interface B {
val valueB: Int
}
data class C(
val value2: String,
override var valueA: Int
) : A()
data class D(
override val valueB: Int,
val valueD: String
) : B

How can I create a Factory that produces objects based on a type or a Class object?

In my Kotlin application I have a few entities (and a data class for each of them) and for each entity I have a service object implementing generic Service<T> interface.
I want to create a Factory of services that will return me a proper service based on a parameter which is a type of entity I want to have a service for. In Java I would pass a Class object into the factory which I could obtain from a static context of the entity class eg. Entity.class but I can't do that in Kotlin. How can I create a Factory that will produce me objects based on a type of an entity?
You're looking for KClass:
Say you have the following classes:
abstract class Parent(val name: String)
class ChildA : Parent("A")
class ChildB : Parent("B")
Then your factory may look like this:
fun <T : Any> factory(c: KClass<T>): T {
return c.createInstance()
}
fun main(args: Array<String>) {
val childA = factory(ChildA::class)
val childB = factory(ChildB::class)
println(childA.name) // A
println(childB.name) // B
}
But there's a better way using reified:
inline fun <reified T : Any> factory(): T {
return T::class.createInstance()
}
Then you can call it like this:
val childA = factory<ChildA>()
val childB = factory<ChildB>()
println(childA.name)
println(childB.name)
Note that without using reified we couldn't do T::class

Searching a workaround for kotlin empty data class primary constructor

With given kotlin code :
sealed class Event(val id:String= UUID.randomUUID().toString(), val timestamp:Instant = Instant.now())
data class BarEvent(val additionalInfo:String):Event()
object FooEvent:Event()
// data class CorrectFooEvent():Event() // invalid kotlin
fun main(args: Array<String>) {
val b1 = BarEvent("b1")
val f1 = FooEvent
Thread.sleep(1000)
val b2 = BarEvent("b2")
val f2 = FooEvent
println("${b1.id} ${b1.timestamp} $b1")
println("${f1.id} ${f1.timestamp} $f1")
println("${b2.id} ${b2.timestamp} $b2")
println("${f2.id} ${f2.timestamp} $f2")
}
There is no issue with BarEvent.
But as FooEvent has no more parameter than the ones in Event, I would like it to have empty constructor. It's not authorized for data class, so I made it an object. But object is singleton, so it doesn't behave as an instanciated event.
The only workaround that I see (keeping the class as a data class) is something like :
sealed class Event(open val id:String= UUID.randomUUID().toString(), open val timestamp:Instant = Instant.now())
data class FooEvent(override val id:String= UUID.randomUUID().toString(), override val timestamp:Instant = Instant.now()):Event()
But it's not very elegant.
Just change FooEvent to a normal class, and add (or generate them using your IDE) toString(), hashCode() and equals(Object) if needed:
class FooEvent: Event() {
override hashCode() = ...
override equals(other: Object) {
...
}
override toString() = ...
}
To make the event a data class, simply add an unused property to it. Not pretty, but as short as it can be in Kotlin at the moment:
data class FooEvent(val dummy: Unit = Unit) : Event()
There seems to be no intention to remove this limitation soon:
Data class without arguments deprecated in 1.0. Why?
Suggestion for parameterless data class