Following code shows serialization and deserialization of simple classes using Jackson. Trouble is during deserialization normal constructor of Root
is not called, and therefore the transient fields name
of Leaf
classes do not have values they had when constructed originally. Is there some way how to provide the transient fields with desired values, without having to make them vars? Some custom serializer or some clever annotations?
I do not want to serialize name
values to keep the serialized format as compact as possible - after all the value is given by the data structure and it should be possible to recreate it from the structure again.
import com.fasterxml.jackson.annotation._
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
class Leaf(val value:Int, @transient val name:String) {
def this(@JsonProperty value:Int) = this(value,"")
}
class Root(val a: Leaf, val b:Leaf)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val root = new Root(new Leaf(1,"a"), new Leaf(2, "b"))
val out = om.writeValueAsString(root)
println(out)
val test = om.readValue(out, classOf[Root])
}
Even if Leaf
objects are separate JVM objects, from serialization point of view they can be handled as part of the Root
object and all the naming can be done by its constructor. For this constructor params need to be annotated and getters created and annotated accessing inner Leaf
values, while the Leaf
values itself are marked @transient
:
class Leaf(val value:Int, val name:String)
class Root(
@(JsonProperty @param)("a") aVal: Int,
@(JsonProperty @param)("b") bVal:Int
) {
@transient val a = new Leaf(aVal,"a")
@transient val b = new Leaf(bVal,"b")
@(JsonProperty @getter) def getA = a.value
@(JsonProperty @getter) def getB = b.value
}
Another option is to use @JsonDeserialier(as=xxx) annotation, then you need to create subclasses for each transient value needed:
class LeafA(value:Int) extends Leaf(value,"a")
class LeafB(value:Int) extends Leaf(value,"b")
case class Root(
@JsonDeserialize(as=classOf[LeafA]) a: Leaf,
@JsonDeserialize(as=classOf[LeafB]) b: Leaf
)