From 9fac4857a0a0bb9939a86d6c0ea58ddfb7ce3762 Mon Sep 17 00:00:00 2001 From: Brendan Doyle Date: Fri, 1 Sep 2023 09:51:33 -0700 Subject: [PATCH] support rollback from pekko migration --- README.md | 4 ++++ build.sbt | 2 +- .../persistence/mongodb/MongoDataModel.scala | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 43da800c..5c39ee1d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ * Test suite verifies against MongoDB 3.6, 4.0, 4.2 +### Preparing to migrate to Apache Pekko? Use 4.x Series. + +* Provides forwards compatibility for Akka / Pekko features that persist internal class names, allowing for you to safely roll back your application after migration. + ### Using Akka 2.6? Use 3.x Series. [![Build Status](https://travis-ci.com/scullxbones/akka-persistence-mongo.svg?branch=master)](https://travis-ci.org/scullxbones/akka-persistence-mongo) ![Maven Central 2.12](https://maven-badges.herokuapp.com/maven-central/com.github.scullxbones/akka-persistence-mongo-common_2.12/badge.svg) diff --git a/build.sbt b/build.sbt index 9fa5b351..15502207 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val releaseV = "3.0.8" +val releaseV = "4.0.0" val scala212V = "2.12.15" val scala213V = "2.13.7" diff --git a/common/src/main/scala/akka/contrib/persistence/mongodb/MongoDataModel.scala b/common/src/main/scala/akka/contrib/persistence/mongodb/MongoDataModel.scala index 9d410a32..5022c989 100644 --- a/common/src/main/scala/akka/contrib/persistence/mongodb/MongoDataModel.scala +++ b/common/src/main/scala/akka/contrib/persistence/mongodb/MongoDataModel.scala @@ -8,7 +8,7 @@ import akka.actor.ActorRef import akka.persistence.journal.Tagged import akka.persistence.query.{EventEnvelope, Offset} import akka.persistence.{AtomicWrite, PersistentRepr} -import akka.serialization.{Serialization, SerializerWithStringManifest} +import akka.serialization.{Serialization, Serializer, SerializerWithStringManifest} import scala.collection.immutable.{Seq => ISeq} import scala.language.existentials @@ -51,15 +51,28 @@ case class Serialized[C <: AnyRef](bytes: Array[Byte], lazy val content: C = { val clazz = loadClass.getClassFor[X forSome { type X <: AnyRef }](className) + Try(tryDeserialize(clazz, clazz.flatMap(c => Try(ser.serializerFor(c))))) + .recover({ + case _ if className.startsWith("org.apache.pekko.") => + val backwardsCompatClazz = loadClass.getClassFor[X forSome { type X <: AnyRef }](className.replaceFirst("org.apache.pekko", "akka")) + tryDeserialize(backwardsCompatClazz, backwardsCompatClazz.flatMap(c => Try(ser.serializerFor(c)))) + case x => throw x + }) match { + case Failure(x) => throw x + case Success(deser) => deser + } + } - val tried = (serializedManifest,serializerId,clazz.flatMap(c => Try(ser.serializerFor(c)))) match { + private def tryDeserialize(clazz: Try[Class[_ <: X forSome {type X <: AnyRef}]], + serializer: Try[Serializer]): C = { + val tried = (serializedManifest, serializerId, serializer) match { // Manifest was serialized, class exists ~ prefer read-time configuration case (Some(manifest), _, Success(clazzSer)) => ser.deserialize(bytes, clazzSer.identifier, manifest) // No manifest id serialized, prefer read-time configuration case (None, _, Success(clazzSer)) => - ser.deserialize[X forSome { type X <: AnyRef }](bytes, clazzSer.identifier, clazz.toOption) + ser.deserialize[X forSome {type X <: AnyRef}](bytes, clazzSer.identifier, clazz.toOption) // Manifest, id were serialized, class doesn't exist - use write-time configuration case (Some(manifest), Some(id), Failure(_)) =>