Jackson-based JSON and CBOR serialization capabilities for the Akka toolkit, enabling efficient serialization and deserialization of Akka messages and persistent events.
—
The ObjectMapper management system provides centralized creation and configuration of Jackson ObjectMapper instances. This allows for consistent configuration across your application while supporting multiple serialization bindings with different settings.
The main provider class manages a registry of ObjectMapper instances, each with a unique binding name.
/**
* Registry of shared `ObjectMapper` instances, each with its unique `bindingName`.
*/
final class JacksonObjectMapperProvider(system: ExtendedActorSystem) extends Extension {
/**
* Returns an existing Jackson `ObjectMapper` or creates a new instance.
* The returned `ObjectMapper` must not be modified after creation.
*
* @param bindingName name of this `ObjectMapper`
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON use `None`
* @return configured ObjectMapper instance
*/
def getOrCreate(bindingName: String, jsonFactory: Option[JsonFactory]): ObjectMapper
/**
* Creates a new instance of a Jackson `ObjectMapper` with sensible defaults.
*
* @param bindingName name of this `ObjectMapper`
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON use `None`
* @return new ObjectMapper instance
*/
def create(bindingName: String, jsonFactory: Option[JsonFactory]): ObjectMapper
}import akka.actor.ActorSystem
import akka.serialization.jackson.JacksonObjectMapperProvider
val system = ActorSystem("MySystem")
val provider = JacksonObjectMapperProvider(system)For JSON serialization:
val jsonMapper = provider.getOrCreate("my-json-binding", None)For CBOR serialization:
import com.fasterxml.jackson.dataformat.cbor.CBORFactory
val cborMapper = provider.getOrCreate("my-cbor-binding", Some(new CBORFactory()))Creating fresh instances:
// Create a new mapper instead of using cached version
val freshMapper = provider.create("my-binding", None)For advanced customization, you can provide a custom factory that controls ObjectMapper creation and configuration.
/**
* Factory for creating and customizing ObjectMapper instances.
* Create a subclass and override methods to amend the defaults.
*/
class JacksonObjectMapperFactory {
/**
* Override to create custom ObjectMapper instance.
*
* @param bindingName name of this `ObjectMapper`
* @param jsonFactory optional `JsonFactory` for the mapper
* @return new ObjectMapper instance
*/
def newObjectMapper(bindingName: String, jsonFactory: JsonFactory): ObjectMapper
/**
* Override configured Jackson modules.
*
* @param bindingName binding name for this mapper
* @param configuredModules modules configured in akka.serialization.jackson.jackson-modules
* @return modules to be applied to the ObjectMapper
*/
def overrideConfiguredModules(bindingName: String, configuredModules: immutable.Seq[Module]): immutable.Seq[Module]
/**
* Override serialization features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.serialization-features
* @return features to be applied to the ObjectMapper
*/
def overrideConfiguredSerializationFeatures(bindingName: String, configuredFeatures: immutable.Seq[(SerializationFeature, Boolean)]): immutable.Seq[(SerializationFeature, Boolean)]
/**
* Override deserialization features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.deserialization-features
* @return features to be applied to the ObjectMapper
*/
def overrideConfiguredDeserializationFeatures(bindingName: String, configuredFeatures: immutable.Seq[(DeserializationFeature, Boolean)]): immutable.Seq[(DeserializationFeature, Boolean)]
/**
* Override mapper features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.mapper-features
* @return features to be applied to the ObjectMapper
*/
def overrideConfiguredMapperFeatures(bindingName: String, configuredFeatures: immutable.Seq[(MapperFeature, Boolean)]): immutable.Seq[(MapperFeature, Boolean)]
/**
* Override JSON parser features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.json-parser-features
* @return features to be applied to the ObjectMapper
*/
def overrideConfiguredJsonParserFeatures(bindingName: String, configuredFeatures: immutable.Seq[(JsonParser.Feature, Boolean)]): immutable.Seq[(JsonParser.Feature, Boolean)]
/**
* Override JSON generator features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.json-generator-features
* @return features to be applied to the ObjectMapper
*/
def overrideConfiguredJsonGeneratorFeatures(bindingName: String, configuredFeatures: immutable.Seq[(JsonGenerator.Feature, Boolean)]): immutable.Seq[(JsonGenerator.Feature, Boolean)]
/**
* Override stream read features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.stream-read-features
* @return features to be applied to the JsonFactory
*/
def overrideConfiguredStreamReadFeatures(bindingName: String, configuredFeatures: immutable.Seq[(StreamReadFeature, Boolean)]): immutable.Seq[(StreamReadFeature, Boolean)]
/**
* Override stream write features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.stream-write-features
* @return features to be applied to the JsonFactory
*/
def overrideConfiguredStreamWriteFeatures(bindingName: String, configuredFeatures: immutable.Seq[(StreamWriteFeature, Boolean)]): immutable.Seq[(StreamWriteFeature, Boolean)]
/**
* Override JSON read features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.json-read-features
* @return features to be applied to the JsonFactory
*/
def overrideConfiguredJsonReadFeatures(bindingName: String, configuredFeatures: immutable.Seq[(JsonReadFeature, Boolean)]): immutable.Seq[(JsonReadFeature, Boolean)]
/**
* Override JSON write features.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures features configured in akka.serialization.jackson.json-write-features
* @return features to be applied to the JsonFactory
*/
def overrideConfiguredJsonWriteFeatures(bindingName: String, configuredFeatures: immutable.Seq[(JsonWriteFeature, Boolean)]): immutable.Seq[(JsonWriteFeature, Boolean)]
/**
* Override visibility settings.
*
* @param bindingName binding name for this mapper
* @param configuredFeatures visibility settings configured in akka.serialization.jackson.visibility
* @return visibility settings to be applied to the ObjectMapper
*/
def overrideConfiguredVisibility(bindingName: String, configuredFeatures: immutable.Seq[(PropertyAccessor, JsonAutoDetect.Visibility)]): immutable.Seq[(PropertyAccessor, JsonAutoDetect.Visibility)]
}class MyCustomFactory extends JacksonObjectMapperFactory {
override def newObjectMapper(bindingName: String, jsonFactory: JsonFactory): ObjectMapper = {
val mapper = JsonMapper.builder(jsonFactory).build()
// Add custom configuration
mapper.configure(SerializationFeature.INDENT_OUTPUT, true)
mapper
}
override def overrideConfiguredModules(bindingName: String, configuredModules: immutable.Seq[Module]): immutable.Seq[Module] = {
// Add a custom module
configuredModules :+ new MyCustomJacksonModule()
}
}To use a custom factory, provide it during ActorSystem creation:
/**
* Setup for defining a custom JacksonObjectMapperFactory.
*/
final class JacksonObjectMapperProviderSetup(val factory: JacksonObjectMapperFactory) extends Setup
object JacksonObjectMapperProviderSetup {
/**
* Create setup with custom factory (Scala API).
*
* @param factory custom JacksonObjectMapperFactory
* @return setup instance for ActorSystem
*/
def apply(factory: JacksonObjectMapperFactory): JacksonObjectMapperProviderSetup
/**
* Create setup with custom factory (Java API).
*
* @param factory custom JacksonObjectMapperFactory
* @return setup instance for ActorSystem
*/
def create(factory: JacksonObjectMapperFactory): JacksonObjectMapperProviderSetup
}import akka.actor.ActorSystem
import akka.actor.setup.ActorSystemSetup
import akka.serialization.jackson.{JacksonObjectMapperProviderSetup, JacksonObjectMapperFactory}
val customFactory = new MyCustomFactory()
val setup = JacksonObjectMapperProviderSetup(customFactory)
val actorSystemSetup = ActorSystemSetup(setup)
val system = ActorSystem("MySystem", actorSystemSetup)The ObjectMapper provider integrates with Akka configuration system, reading settings from akka.serialization.jackson section:
akka.serialization.jackson {
# Global settings
jackson-modules += "com.example.MyModule"
# Binding-specific settings
my-json-binding {
serialization-features {
INDENT_OUTPUT = on
}
}
my-cbor-binding {
compression {
algorithm = lz4
compress-larger-than = 1 KiB
}
}
}import akka.serialization.jackson.JacksonObjectMapperProvider
val config = JacksonObjectMapperProvider.configForBinding("my-binding", system.settings.config)
val isCompressionEnabled = config.getString("compression.algorithm") != "off"getOrCreate() for shared mappers - Reuses configured instances for better performancecreate() for specialized mappers - When you need mapper-specific customizationsInstall with Tessl CLI
npx tessl i tessl/maven-com-typesafe-akka--akka-serialization-jackson