altoo-ag/akka-kryo-serialization

Scala product serializer only works for simple case classes

nvollmar opened this issue · 11 comments

The product serializer relies on product arity to serialize a case class which will fail for case classes with an additional parameter list:

  case class SimpleProduct(id: UUID, long: Long) // can be serialized
  case class CurriedProduct(id: UUID)(long: Long) // will fail on de-serialization!

Reason:
In both cases getDeclaredConstructors will return a constructor with the same parameters two (UUID, Long). But productArity will return 2 for SimpleProduct but 1 for CurriedProduct.

Proposal:
The ScalaProductSerializer should not produce something that fails on de-serialization.
Either fix it or remove it (currently not configured by default anyway).

To fix it we have several options:

  • Extend to handle all kinds of case classes with extended reflection
  • Detect and delegate such case classes to another serializer for non-trivial case classes
  • Detect and fail already at serialization so a custom serializer can be configured in such cases

should not produce something that fails on de-serialization.

100% agree

And as long as kryo already serializes case classes properly I opt for delete. (@nvollmar except if this serializer provides better performance... have you checked that?)

luben commented

If we remove the product serializer, will it change the behaviour? E.g. if a case class has a private field (not that it's good idea) that is not marked @transient?

Yes, it would change the behavior. And if anyone actually was using it it would be a breaking change. I’ll change the pull request and deprecate and document it for now. Should be removed with 2.0 then.

@danischroeter speed seems roughly the same, but size is actually considerably bigger. So I don’t see any benefit.

luben commented

An option is to fall-back to kryo's field serializer if productArity != getDeclaredConstructors.head.getParameters.length

To clarify, the serializer is not used by default, you have to manually register it.
As is, the kryo serializer is used for case classes which seems to work fine/even better.

luben commented

Fair enough - may be just declare it deprecated and mention the cases it can't handle.

We might even add a log.warn if this serializer is registered so if anyone is using it we can make him aware that this serializer is less efficient and does not work for all cases.

Deprecated and added warning

luben commented

@danischroeter , I interpret @nvollmar's comment that the product serializer was producing smaller serialized payloads. Adding a log.warn on registration is a good way to way to make deprecation more visible.

@luben product serializer's result size was actually larger

simple example of a case class with a uuid and a long:

kryo: [48,1,1,-7,-59,-126,-92,-126,-65,-35,-10,-36,-97,-56,-51,-14,-70,-3,-20,-19,12,2] (22 bytes)
product: [48,1,2,49,1,-7,-59,-126,-92,-126,-65,-35,-10,-36,-97,-56,-51,-14,-70,-3,-20,-19,12,9,2] (25 bytes)

this is with both classes registered - with fallback to FQCN:
kryo: 113 bytes
product: 131 bytes