Skip to content

Instantly share code, notes, and snippets.

@thesamet
Last active November 30, 2020 05:50
Show Gist options
  • Save thesamet/5d0349b40d3dc92859a1a2eafba448d5 to your computer and use it in GitHub Desktop.
Save thesamet/5d0349b40d3dc92859a1a2eafba448d5 to your computer and use it in GitHub Desktop.
Akka serializer for ScalaPB messages
akka {
actor {
serializers {
scalapb = "protoser.ScalaPbSerializer"
}
serialization-bindings {
"com.trueaccord.scalapb.GeneratedMessage" = scalapb
}
serialization-identifiers {
"protoser.ScalaPbSerializer" = 10000
}
}
}
package protoser
import java.util.concurrent.atomic.AtomicReference
import akka.actor.ExtendedActorSystem
import akka.serialization.BaseSerializer
import com.trueaccord.scalapb.GeneratedMessageCompanion
class ScalaPbSerializer(val system: ExtendedActorSystem) extends BaseSerializer {
private val classToCompanionMapRef = new AtomicReference[Map[Class[_], GeneratedMessageCompanion[_]]](Map.empty)
override def toBinary(o: AnyRef): Array[Byte] = o match {
case e: com.trueaccord.scalapb.GeneratedMessage => e.toByteArray
case _ => throw new IllegalArgumentException("Need a subclass of com.trueaccord.scalapb.GeneratedMessage")
}
override def includeManifest: Boolean = true
override def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): AnyRef = {
manifest match {
case Some(clazz) =>
@scala.annotation.tailrec
def messageCompanion(companion: GeneratedMessageCompanion[_] = null): GeneratedMessageCompanion[_] = {
val classToCompanion = classToCompanionMapRef.get()
classToCompanion.get(clazz) match {
case Some(cachedCompanion) => cachedCompanion
case None =>
val uncachedCompanion =
if (companion eq null) Class.forName(clazz.getName + "$", true, clazz.getClassLoader)
.getField("MODULE$").get().asInstanceOf[GeneratedMessageCompanion[_]]
else companion
if (classToCompanionMapRef.compareAndSet(classToCompanion, classToCompanion.updated(clazz, uncachedCompanion)))
uncachedCompanion
else
messageCompanion(uncachedCompanion)
}
}
messageCompanion().parseFrom(bytes).asInstanceOf[AnyRef]
case _ => throw new IllegalArgumentException("Need a ScalaPB companion class to be able to deserialize.")
}
}
}
@jchapuis
Copy link

Nice! this probably needs to be adapted to import the new namespace: import scalapb.GeneratedMessageCompanion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment