JacksonCborSerializer should use CBOR ofc, #28918
* When we updated to Jackson 2.10 (prior Akka 2.6.0) the new JsonFactoryBuilder was used. That doesn't preserve the formatParserFeatures and formatGeneratorFeatures from the base CBORFactory and therefore the format was plain JSON. * rolling update compatibility
This commit is contained in:
parent
6361bdb153
commit
ef9a2c79c6
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
|
||||
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'
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue