Search code examples
scalajacksondeserializationslf4jakka-cluster

InvalidDefinitionException: Cannot construct instance of `org.slf4j.Logger`


I have a akka cluster of microservices running on nodes. I'm trying to use the Jackson serializer for application specific messages exchanged between the nodes (microservices). My code is written in scala, not Java

I'm using scala 'case class' as akka messages exchanged between actors and each message (case class) have a val LOG:org.slf4j.Logger built in to log specific business logic processing information.

When I send messages between nodes I'm getting the exception

WARN akka.remote.artery.Deserializer - Failed to deserialize message from [akka://[email protected]:25251] with serializer id [33] and manifest [com...MyCaseClassMessage]. com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.slf4j.Logger (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: ..."[truncated 'n' bytes]; line: 'n', column: 'n'] (through reference chain: com...MyCaseClassMessage["LOG"])

My case class essentially is something like:

case class MyCaseClassMessage()
  extends CborSerializable {

  override val LOG:Logger = LoggerFactory.getLogger(classOf[MyCaseClassMessage])

  val businessLogic:Array[Byte] = ...
  def apply():Array[Byte] = ...

}

I have no idea of how to specify to Jackson how to serialize and (or) deserialize a "val LOG:Logger" in my case class. I just know that if I remove my Logger, substituing it to (for example) println("message") I don't have any problem with serialization and deserialization.

Any help?


Solution

  • Because Jackson relies on reflection and does not understand the convention in Scala case classes that only the constructor parameters are required for defining the message, it will attempt to serialize every field of the object.

    The LOG field can be ignored by Jackson by annotating it with an @JsonIgnore annotation (com.fasterxml.jackson.annotation.JsonIgnore):

    @JsonIgnore
    override val LOG: Logger = LoggerFactory.getLogger(classOf[MyCaseClassMessage])