Last active
October 10, 2015 06:53
-
-
Save ahjohannessen/ce43cf45607b9dd9050b to your computer and use it in GitHub Desktop.
Reflection based serializer for ScalaPB generated case classes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.Method | |
import java.util.concurrent.atomic.AtomicReference | |
import akka.actor.ExtendedActorSystem | |
import akka.serialization.Serializer | |
import com.trueaccord.scalapb.GeneratedMessage | |
import scala.annotation.tailrec | |
/** | |
* This Serializer serializes `com.trueaccord.scalapb.GeneratedMessage`s | |
*/ | |
class ProtobufSerializer(val system: ExtendedActorSystem) extends Serializer { | |
import ProtobufSerializer._ | |
private val parsingMethodBindingRef = new AtomicReference[Map[Class[_], Method]](Map.empty) | |
def identifier = 200 | |
def includeManifest = true | |
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = clazz match { | |
case Some(clz) ⇒ | |
@tailrec | |
def parsingMethod(method: Method = null): Method = { | |
val parsingMethodBinding = parsingMethodBindingRef.get() | |
parsingMethodBinding.get(clz) match { | |
case Some(cachedParsingMethod) ⇒ cachedParsingMethod | |
case None ⇒ | |
val unCachedParsingMethod = | |
if (method eq null) clz.getDeclaredMethod("parseFrom", ARRAY_OF_BYTE_ARRAY: _*) | |
else method | |
if (parsingMethodBindingRef.compareAndSet(parsingMethodBinding, parsingMethodBinding.updated(clz, unCachedParsingMethod))) | |
unCachedParsingMethod | |
else | |
parsingMethod(unCachedParsingMethod) | |
} | |
} | |
parsingMethod().invoke(null, bytes).asInstanceOf[GeneratedMessage] | |
case None ⇒ throw new IllegalArgumentException( | |
"Need a protobuf message class to be able to serialize bytes using protobuf" | |
) | |
} | |
def toBinary(obj: AnyRef): Array[Byte] = obj match { | |
case message: GeneratedMessage ⇒ message.toByteArray | |
case _ ⇒ throw new IllegalArgumentException( | |
s"Can't serialize a non-protobuf message using protobuf [$obj]" | |
) | |
} | |
} | |
object ProtobufSerializer { | |
private val ARRAY_OF_BYTE_ARRAY = Array[Class[_]](classOf[Array[Byte]]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment