pjfanning / jackson-module-enumeratum

Enumeratum support for Jackson
Apache License 2.0
4 stars 3 forks source link

Failed to deserialize with Lagom #3

Closed ASchmidt84 closed 2 years ago

ASchmidt84 commented 2 years ago

Hi, i am using enumeratum and created a permission enum

sealed abstract class Permission private[permissions](val service: Option[MicroServiceIdentifier],
                                                      val uniqueName: String,
                                                      val description: String) extends EnumEntry {
  override def toString: String = uniqueName
}

object Permission extends Enum[Permission] with PlayJsonEnum[Permission] {
  override def values: immutable.IndexedSeq[Permission] = findValues

//  implicit val format: OFormat[Permission] = derived.oformat()

  implicit val pathParamSerializer: PathParamSerializer[Permission] = new PathParamSerializer[Permission] {
    override def serialize(parameter: Permission): immutable.Seq[String] = immutable.Seq(parameter.uniqueName)

    override def deserialize(parameters: immutable.Seq[String]): Permission = parameters.headOption match {
      case Some(i) => Permission.withName(i)
      case _ => throw new IllegalArgumentException("PermissionValue needs a parameter as string")
    }
  }

  //---------- Security Service User Profile ---------------------------------------

  case object UserChangePasswordSelf extends Permission(Some(MicroServiceIdentifier.SecurityServiceIdentifier), "user_change_own_password_rw", "Own password change")
}

In dev mode all is working fine. In prod mode I get an jackson error.

Failed to deserialize message from [akka://application@********:25520] with serializer id [25] and manifest [a]. com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.coup.avalon.utils.adt.permissions.Permission` (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 ...

in application.conf

akka.actor {
    serialization-bindings {
        # Commands won't use play-json but Akka's jackson support.
        # See https://doc.akka.io/docs/akka/2.6/serialization-jackson.html
        #       "com.example.shoppingcart.impl.ShoppingCart$CommandSerializable" = jackson-json
        "io.coup.avalon.security.impl.user.UserProfile$CommandSerializable" = jackson-json
    }
}

Now my question with adding jackson-module-enumeratum will this work?

Thank you.

pjfanning commented 2 years ago

In theory, yes. The play-json serializer in Permission won't help with akka jackson serialization.

Have a look at https://doc.akka.io/docs/akka/current/serialization-jackson.html#jackson-modules and see if adding "com.github.pjfanning.enumeratum.EnumeratumModule" helps. You will need to add the library as a dependency too in your sbt script.

If this approach doesn't work, you might need to try writing a custom jackson serializer for Permission class. See the part in https://doc.akka.io/docs/akka/current/serialization-jackson.html that describes that does this.

@JsonSerialize(`using` = classOf[DirectionJsonSerializer])
@JsonDeserialize(`using` = classOf[DirectionJsonDeserializer])
ASchmidt84 commented 2 years ago

Hi,

okay I added it. But after build and run I get the error

Could not load configured Jackson module [com.github.pjfanning.enumeratum.EnumeratumModule], please verify classpath dependencies or amend the configuration [akka.serialization.jackson-modules]. Continuing without this module.
java.lang.ClassCastException: class com.fasterxml.jackson.databind.Module is not assignable from class com.github.pjfanning.enumeratum.EnumeratumModule

I added it to sbt don´t know why it does not find.

pjfanning commented 2 years ago

EnumeratumModule does extend com.fasterxml.jackson.databind.Module - I have unit tests to prove it

You will need to talk to the Lagom team. I suspect that you might have jar version mismatches on your classpath.

ASchmidt84 commented 2 years ago

yes i think it too.

pjfanning commented 2 years ago

You also have the option of writing a custom serializer as I suggested above.

ASchmidt84 commented 2 years ago

I will look at write a custom serializer. To get an answer from lightbend is like asking god. 🤣 For better understanding. I change my lib to:

"com.beachape"                 %% "enumeratum-play-json"                          % "1.7.0",
  "com.github.pjfanning" %% "jackson-module-enumeratum" % "2.13.0",
  "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.13.0"

and added to my conf:

akka.actor {
    serialization-bindings {
        # Commands won't use play-json but Akka's jackson support.
        # See https://doc.akka.io/docs/akka/2.6/serialization-jackson.html
        #       "com.example.shoppingcart.impl.ShoppingCart$CommandSerializable" = jackson-json
        "io.coup.avalon.security.impl.user.UserProfile$CommandSerializable" = jackson-json
    }
}

akka.serialization.jackson{
    jackson-modules += "com.fasterxml.jackson.datatype.pcollections.PCollectionsModule"
    jackson-modules += "com.fasterxml.jackson.datatype.guava.GuavaModule"
    jackson-modules += "com.github.pjfanning.enumeratum.EnumeratumModule"
}

Do i need to init the module somewhere additional? Thank yoou for your help

pjfanning commented 2 years ago

I have never used Lagom and I have never used akka jackson integration.

pjfanning commented 2 years ago

One thing to watch out for is that akka tends not to use the latest jackson versions - you might want to try to match the version of your jackson dependencies to the version of jackson that your akka version uses - eg if akka needs 2.12.x, then use a 2.12.x version of jackson-module-scala and jackson-module-enumeratum - if you need jackson 2.11 support, then just use jackson-module-enumeratum 2.12.x and exclude its transitive dependencies so that you don't cause jackson databind to be upgraded - see the exclude support in https://www.scala-sbt.org/1.x/docs/Library-Management.html

pjfanning commented 2 years ago

also read https://discuss.lightbend.com/t/solved-scala-akka-typed-how-to-add-a-jackson-module-to-avoid-de-serialization-error-of-address/7382

pjfanning commented 2 years ago

it might be worth trying

   jackson-modules += "com.github.pjfanning.enumeratum.EnumeratumModule$"

if akka jackson support is using Java reflection, then com.github.pjfanning.enumeratum.EnumeratumModule$ is the name of the class that backs the EnumeratumModule scala object

pjfanning commented 2 years ago

@ASchmidt84 I did a change that might help - https://github.com/pjfanning/jackson-module-enumeratum/issues/4 (there is a published snapshot with this change)

ASchmidt84 commented 2 years ago

@pjfanning the missing $ seems to be the problem 👍 I will have a deeper look

ASchmidt84 commented 2 years ago

Yes this solves it 👍 Great idea! Thank you.