Merge pull request #28920 from akka/wip-28918-cbor-patriknw

JacksonCborSerializer should use CBOR ofc, #28918
This commit is contained in:
Patrik Nordwall 2020-04-20 16:06:04 +02:00 committed by GitHub
commit 1f448cae2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 9 deletions

View file

@ -86,3 +86,32 @@ has been prepared to accept those shorter forms but still emits the old long man
This means that a rolling update will have to go through at least one of 2.6.2, 2.6.3 or 2.6.4 when upgrading to
2.6.5 or higher or else cluster nodes will not be able to communicate during the rolling update.
### 2.6.5 JacksonCborSerializer
Issue: [#28918](https://github.com/akka/akka/issues/28918). JacksonCborSerializer was using plain JSON format
instead of CBOR.
If you have `jackson-cbor` in your `serialization-bindings` a rolling upgrade will have to go through 2.6.5 when
upgrading to 2.6.5 or higher.
In Akka 2.6.5 the `jackson-cbor` binding will still serialize to JSON format to support rolling update from 2.6.4.
It also adds a new binding to be able to deserialize CBOR format when rolling update from 2.6.5 to 2.6.6.
In Akka 2.6.6 the `jackson-cbor` binding will serialize to CBOR and that can be deserialized by 2.6.5. Old
data, such as persistent events, can still be deserialized.
You can start using CBOR format already with Akka 2.6.5 without waiting for the 2.6.6 release. First, perform
a rolling update to Akka 2.6.5 using default configuration. Then change the configuration to:
```
akka.actor {
serializers {
jackson-cbor = "akka.serialization.jackson.JacksonCborSerializer"
}
serialization-identifiers {
jackson-cbor = 33
}
}
```
Perform a second rolling update with the new configuration.

View file

@ -175,6 +175,13 @@ akka.serialization.jackson {
# override the settings in 'akka.serialization.jackson'
jackson-cbor {}
# Issue #28918 for compatibility with data serialized with JacksonCborSerializer in
# Akka 2.6.4 or earlier, which was plain JSON format.
jackson-cbor-264 = ${akka.serialization.jackson.jackson-cbor}
# Issue #28918 temporary in Akka 2.6.5 to support rolling update to 2.6.6.
jackson-cbor-265 = ${akka.serialization.jackson.jackson-cbor}
}
#//#features
@ -195,11 +202,23 @@ akka.serialization.jackson.jackson-json.compression {
akka.actor {
serializers {
jackson-json = "akka.serialization.jackson.JacksonJsonSerializer"
jackson-cbor = "akka.serialization.jackson.JacksonCborSerializer"
jackson-cbor = "akka.serialization.jackson.JacksonJsonSerializer"
# Issue #28918 for compatibility with data serialized with JacksonCborSerializer in
# Akka 2.6.4 or earlier, which was plain JSON format.
jackson-cbor-264 = "akka.serialization.jackson.JacksonJsonSerializer"
# Issue #28918 temporary in Akka 2.6.5 to support rolling update to 2.6.6.
jackson-cbor-265 = "akka.serialization.jackson.JacksonCborSerializer"
}
serialization-identifiers {
jackson-json = 31
jackson-cbor = 32
# Issue #28918 for compatibility with data serialized with JacksonCborSerializer in
# Akka 2.6.4 or earlier, which was plain JSON format.
jackson-cbor-264 = 32
# Issue #28918 temporary in Akka 2.6.5 to support rolling update to 2.6.6.
jackson-cbor-265 = 33
}
serialization-bindings {
# Define bindings for classes or interfaces use Jackson serializer, e.g.

View file

@ -11,6 +11,7 @@ import scala.collection.immutable
import scala.compat.java8.OptionConverters._
import scala.util.Failure
import scala.util.Success
import akka.actor.ActorSystem
import akka.actor.ClassicActorSystemProvider
import akka.actor.DynamicAccess
@ -70,9 +71,15 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
config: Config,
baseJsonFactory: Option[JsonFactory]): JsonFactory = {
val jsonFactoryBuilder = baseJsonFactory match {
case Some(jsonFactory) => new JsonFactoryBuilder(jsonFactory)
case None => new JsonFactoryBuilder()
val jsonFactory: JsonFactory = baseJsonFactory match {
case Some(factory) =>
// Issue #28918 not possible to use new JsonFactoryBuilder(jsonFactory) here.
// It doesn't preserve the formatParserFeatures and formatGeneratorFeatures in
// CBORFactor. Therefore we use JsonFactory and configure the features with mappedFeature
// instead of using JsonFactoryBuilder (new in Jackson 2.10.0).
factory
case None =>
new JsonFactoryBuilder().build()
}
val configuredStreamReadFeatures =
@ -82,7 +89,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
val streamReadFeatures =
objectMapperFactory.overrideConfiguredStreamReadFeatures(bindingName, configuredStreamReadFeatures)
streamReadFeatures.foreach {
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
}
val configuredStreamWriteFeatures =
@ -92,7 +99,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
val streamWriteFeatures =
objectMapperFactory.overrideConfiguredStreamWriteFeatures(bindingName, configuredStreamWriteFeatures)
streamWriteFeatures.foreach {
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
}
val configuredJsonReadFeatures =
@ -102,7 +109,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
val jsonReadFeatures =
objectMapperFactory.overrideConfiguredJsonReadFeatures(bindingName, configuredJsonReadFeatures)
jsonReadFeatures.foreach {
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
}
val configuredJsonWriteFeatures =
@ -112,10 +119,10 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
val jsonWriteFeatures =
objectMapperFactory.overrideConfiguredJsonWriteFeatures(bindingName, configuredJsonWriteFeatures)
jsonWriteFeatures.foreach {
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
}
jsonFactoryBuilder.build()
jsonFactory
}
private def configureObjectMapperFeatures(

View file

@ -4,6 +4,7 @@
package akka.serialization.jackson
import java.nio.charset.StandardCharsets
import java.time.Duration
import java.time.Instant
import java.time.LocalDateTime
@ -17,6 +18,7 @@ import java.util.logging.FileHandler
import scala.collection.immutable
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.actor.Address
@ -569,6 +571,17 @@ class JacksonJsonSerializerSpec extends JacksonSerializerSpec("jackson-json") {
""")(sys => checkSerialization(Elephant("Dumbo", 1), sys))
}
}
// issue #28918
"cbor compatibility for reading json" in {
val msg = SimpleCommand("abc")
val jsonSerializer = serializerFor(msg)
jsonSerializer.identifier should ===(31)
val manifest = jsonSerializer.manifest(msg)
val bytes = jsonSerializer.toBinary(msg)
val deserialized = serialization().deserialize(bytes, 32, manifest).get
deserialized should be(msg)
}
}
}
@ -626,6 +639,20 @@ abstract class JacksonSerializerSpec(serializerName: String)
val manifest = serializer.manifest(obj)
val serializerId = serializer.identifier
val blob = serializeToBinary(obj)
// Issue #28918, check that CBOR format is used (not JSON).
if (blob.length > 0) {
serializer match {
case _: JacksonJsonSerializer =>
if (!JacksonSerializer.isGZipped(blob))
new String(blob.take(1), StandardCharsets.UTF_8) should ===("{")
case _: JacksonCborSerializer =>
new String(blob.take(1), StandardCharsets.UTF_8) should !==("{")
case _ =>
throw new IllegalArgumentException(s"Unexpected serializer $serializer")
}
}
val deserialized = deserializeFromBinary(blob, serializerId, manifest, sys)
deserialized should ===(obj)
}