Merge pull request #28920 from akka/wip-28918-cbor-patriknw
JacksonCborSerializer should use CBOR ofc, #28918
This commit is contained in:
commit
1f448cae2c
4 changed files with 91 additions and 9 deletions
|
|
@ -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
|
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 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.
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,13 @@ akka.serialization.jackson {
|
||||||
# override the settings in 'akka.serialization.jackson'
|
# override the settings in 'akka.serialization.jackson'
|
||||||
jackson-cbor {}
|
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
|
#//#features
|
||||||
|
|
||||||
|
|
@ -195,11 +202,23 @@ akka.serialization.jackson.jackson-json.compression {
|
||||||
akka.actor {
|
akka.actor {
|
||||||
serializers {
|
serializers {
|
||||||
jackson-json = "akka.serialization.jackson.JacksonJsonSerializer"
|
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 {
|
serialization-identifiers {
|
||||||
jackson-json = 31
|
jackson-json = 31
|
||||||
jackson-cbor = 32
|
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 {
|
serialization-bindings {
|
||||||
# Define bindings for classes or interfaces use Jackson serializer, e.g.
|
# Define bindings for classes or interfaces use Jackson serializer, e.g.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import scala.collection.immutable
|
||||||
import scala.compat.java8.OptionConverters._
|
import scala.compat.java8.OptionConverters._
|
||||||
import scala.util.Failure
|
import scala.util.Failure
|
||||||
import scala.util.Success
|
import scala.util.Success
|
||||||
|
|
||||||
import akka.actor.ActorSystem
|
import akka.actor.ActorSystem
|
||||||
import akka.actor.ClassicActorSystemProvider
|
import akka.actor.ClassicActorSystemProvider
|
||||||
import akka.actor.DynamicAccess
|
import akka.actor.DynamicAccess
|
||||||
|
|
@ -70,9 +71,15 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
|
||||||
config: Config,
|
config: Config,
|
||||||
baseJsonFactory: Option[JsonFactory]): JsonFactory = {
|
baseJsonFactory: Option[JsonFactory]): JsonFactory = {
|
||||||
|
|
||||||
val jsonFactoryBuilder = baseJsonFactory match {
|
val jsonFactory: JsonFactory = baseJsonFactory match {
|
||||||
case Some(jsonFactory) => new JsonFactoryBuilder(jsonFactory)
|
case Some(factory) =>
|
||||||
case None => new JsonFactoryBuilder()
|
// 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 =
|
val configuredStreamReadFeatures =
|
||||||
|
|
@ -82,7 +89,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
|
||||||
val streamReadFeatures =
|
val streamReadFeatures =
|
||||||
objectMapperFactory.overrideConfiguredStreamReadFeatures(bindingName, configuredStreamReadFeatures)
|
objectMapperFactory.overrideConfiguredStreamReadFeatures(bindingName, configuredStreamReadFeatures)
|
||||||
streamReadFeatures.foreach {
|
streamReadFeatures.foreach {
|
||||||
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
val configuredStreamWriteFeatures =
|
val configuredStreamWriteFeatures =
|
||||||
|
|
@ -92,7 +99,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
|
||||||
val streamWriteFeatures =
|
val streamWriteFeatures =
|
||||||
objectMapperFactory.overrideConfiguredStreamWriteFeatures(bindingName, configuredStreamWriteFeatures)
|
objectMapperFactory.overrideConfiguredStreamWriteFeatures(bindingName, configuredStreamWriteFeatures)
|
||||||
streamWriteFeatures.foreach {
|
streamWriteFeatures.foreach {
|
||||||
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
val configuredJsonReadFeatures =
|
val configuredJsonReadFeatures =
|
||||||
|
|
@ -102,7 +109,7 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
|
||||||
val jsonReadFeatures =
|
val jsonReadFeatures =
|
||||||
objectMapperFactory.overrideConfiguredJsonReadFeatures(bindingName, configuredJsonReadFeatures)
|
objectMapperFactory.overrideConfiguredJsonReadFeatures(bindingName, configuredJsonReadFeatures)
|
||||||
jsonReadFeatures.foreach {
|
jsonReadFeatures.foreach {
|
||||||
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
val configuredJsonWriteFeatures =
|
val configuredJsonWriteFeatures =
|
||||||
|
|
@ -112,10 +119,10 @@ object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvid
|
||||||
val jsonWriteFeatures =
|
val jsonWriteFeatures =
|
||||||
objectMapperFactory.overrideConfiguredJsonWriteFeatures(bindingName, configuredJsonWriteFeatures)
|
objectMapperFactory.overrideConfiguredJsonWriteFeatures(bindingName, configuredJsonWriteFeatures)
|
||||||
jsonWriteFeatures.foreach {
|
jsonWriteFeatures.foreach {
|
||||||
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
case (feature, value) => jsonFactory.configure(feature.mappedFeature, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonFactoryBuilder.build()
|
jsonFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
private def configureObjectMapperFeatures(
|
private def configureObjectMapperFeatures(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package akka.serialization.jackson
|
package akka.serialization.jackson
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
@ -17,6 +18,7 @@ import java.util.logging.FileHandler
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import akka.actor.ActorSystem
|
import akka.actor.ActorSystem
|
||||||
import akka.actor.Address
|
import akka.actor.Address
|
||||||
|
|
@ -569,6 +571,17 @@ class JacksonJsonSerializerSpec extends JacksonSerializerSpec("jackson-json") {
|
||||||
""")(sys => checkSerialization(Elephant("Dumbo", 1), sys))
|
""")(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 manifest = serializer.manifest(obj)
|
||||||
val serializerId = serializer.identifier
|
val serializerId = serializer.identifier
|
||||||
val blob = serializeToBinary(obj)
|
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)
|
val deserialized = deserializeFromBinary(blob, serializerId, manifest, sys)
|
||||||
deserialized should ===(obj)
|
deserialized should ===(obj)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue