2018-02-11 19:56:52 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2016-2019 Lightbend Inc. <https://www.lightbend.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.serialization.jackson
|
|
|
|
|
|
2019-07-12 13:31:24 +02:00
|
|
|
import java.util.Optional
|
2018-02-11 19:56:52 +01:00
|
|
|
import java.util.concurrent.ConcurrentHashMap
|
|
|
|
|
|
|
|
|
|
import scala.collection.immutable
|
2019-07-12 13:31:24 +02:00
|
|
|
import scala.compat.java8.OptionConverters._
|
2018-02-11 19:56:52 +01:00
|
|
|
import scala.util.Failure
|
|
|
|
|
import scala.util.Success
|
|
|
|
|
import akka.actor.ActorSystem
|
|
|
|
|
import akka.actor.DynamicAccess
|
|
|
|
|
import akka.actor.ExtendedActorSystem
|
|
|
|
|
import akka.actor.Extension
|
|
|
|
|
import akka.actor.ExtensionId
|
|
|
|
|
import akka.actor.ExtensionIdProvider
|
|
|
|
|
import akka.actor.setup.Setup
|
|
|
|
|
import akka.annotation.InternalStableApi
|
|
|
|
|
import akka.event.Logging
|
|
|
|
|
import akka.event.LoggingAdapter
|
|
|
|
|
import akka.util.unused
|
|
|
|
|
import com.fasterxml.jackson.annotation.JsonAutoDetect
|
|
|
|
|
import com.fasterxml.jackson.annotation.JsonCreator
|
|
|
|
|
import com.fasterxml.jackson.annotation.PropertyAccessor
|
|
|
|
|
import com.fasterxml.jackson.core.JsonFactory
|
2019-10-02 22:58:11 -04:00
|
|
|
import com.fasterxml.jackson.core.JsonFactoryBuilder
|
2018-02-11 19:56:52 +01:00
|
|
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
2019-08-16 05:33:47 -04:00
|
|
|
import com.fasterxml.jackson.databind.MapperFeature
|
2018-02-11 19:56:52 +01:00
|
|
|
import com.fasterxml.jackson.databind.Module
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper
|
|
|
|
|
import com.fasterxml.jackson.databind.SerializationFeature
|
|
|
|
|
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule
|
|
|
|
|
import com.typesafe.config.Config
|
2019-08-16 05:33:47 -04:00
|
|
|
import com.fasterxml.jackson.core.JsonParser
|
|
|
|
|
import com.fasterxml.jackson.core.JsonGenerator
|
2019-10-02 22:58:11 -04:00
|
|
|
import com.fasterxml.jackson.core.StreamReadFeature
|
|
|
|
|
import com.fasterxml.jackson.core.StreamWriteFeature
|
|
|
|
|
import com.fasterxml.jackson.core.json.JsonReadFeature
|
|
|
|
|
import com.fasterxml.jackson.core.json.JsonWriteFeature
|
|
|
|
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
object JacksonObjectMapperProvider extends ExtensionId[JacksonObjectMapperProvider] with ExtensionIdProvider {
|
|
|
|
|
override def get(system: ActorSystem): JacksonObjectMapperProvider = super.get(system)
|
|
|
|
|
|
|
|
|
|
override def lookup = JacksonObjectMapperProvider
|
|
|
|
|
|
|
|
|
|
override def createExtension(system: ExtendedActorSystem): JacksonObjectMapperProvider =
|
|
|
|
|
new JacksonObjectMapperProvider(system)
|
|
|
|
|
|
2019-06-02 11:27:03 +02:00
|
|
|
/**
|
|
|
|
|
* The configuration for a given `bindingName`.
|
|
|
|
|
*/
|
|
|
|
|
def configForBinding(bindingName: String, systemConfig: Config): Config = {
|
|
|
|
|
val basePath = "akka.serialization.jackson"
|
|
|
|
|
val baseConf = systemConfig.getConfig("akka.serialization.jackson")
|
|
|
|
|
if (systemConfig.hasPath(s"$basePath.$bindingName"))
|
|
|
|
|
systemConfig.getConfig(s"$basePath.$bindingName").withFallback(baseConf)
|
|
|
|
|
else
|
|
|
|
|
baseConf
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-02 22:58:11 -04:00
|
|
|
private def createJsonFactory(
|
2019-06-02 11:27:03 +02:00
|
|
|
bindingName: String,
|
2018-02-11 19:56:52 +01:00
|
|
|
objectMapperFactory: JacksonObjectMapperFactory,
|
|
|
|
|
config: Config,
|
2019-10-02 22:58:11 -04:00
|
|
|
baseJsonFactory: Option[JsonFactory]): JsonFactory = {
|
2019-06-13 16:17:04 +01:00
|
|
|
|
2019-10-02 22:58:11 -04:00
|
|
|
val jsonFactoryBuilder = baseJsonFactory match {
|
|
|
|
|
case Some(jsonFactory) => new JsonFactoryBuilder(jsonFactory)
|
|
|
|
|
case None => new JsonFactoryBuilder()
|
|
|
|
|
}
|
2018-02-11 19:56:52 +01:00
|
|
|
|
2019-10-02 22:58:11 -04:00
|
|
|
val configuredStreamReadFeatures =
|
|
|
|
|
features(config, "stream-read-features").map {
|
|
|
|
|
case (enumName, value) => StreamReadFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val streamReadFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredStreamReadFeatures(bindingName, configuredStreamReadFeatures)
|
|
|
|
|
streamReadFeatures.foreach {
|
|
|
|
|
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
|
|
|
|
}
|
2018-02-11 19:56:52 +01:00
|
|
|
|
2019-10-02 22:58:11 -04:00
|
|
|
val configuredStreamWriteFeatures =
|
|
|
|
|
features(config, "stream-write-features").map {
|
|
|
|
|
case (enumName, value) => StreamWriteFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val streamWriteFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredStreamWriteFeatures(bindingName, configuredStreamWriteFeatures)
|
|
|
|
|
streamWriteFeatures.foreach {
|
|
|
|
|
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val configuredJsonReadFeatures =
|
|
|
|
|
features(config, "json-read-features").map {
|
|
|
|
|
case (enumName, value) => JsonReadFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val jsonReadFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredJsonReadFeatures(bindingName, configuredJsonReadFeatures)
|
|
|
|
|
jsonReadFeatures.foreach {
|
|
|
|
|
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val configuredJsonWriteFeatures =
|
|
|
|
|
features(config, "json-write-features").map {
|
|
|
|
|
case (enumName, value) => JsonWriteFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val jsonWriteFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredJsonWriteFeatures(bindingName, configuredJsonWriteFeatures)
|
|
|
|
|
jsonWriteFeatures.foreach {
|
|
|
|
|
case (feature, value) => jsonFactoryBuilder.configure(feature, value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jsonFactoryBuilder.build()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def configureObjectMapperFeatures(
|
|
|
|
|
bindingName: String,
|
|
|
|
|
objectMapper: ObjectMapper,
|
|
|
|
|
objectMapperFactory: JacksonObjectMapperFactory,
|
|
|
|
|
config: Config): Unit = {
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
val configuredSerializationFeatures =
|
2019-06-02 11:27:03 +02:00
|
|
|
features(config, "serialization-features").map {
|
2018-02-11 19:56:52 +01:00
|
|
|
case (enumName, value) => SerializationFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val serializationFeatures =
|
2019-06-02 11:27:03 +02:00
|
|
|
objectMapperFactory.overrideConfiguredSerializationFeatures(bindingName, configuredSerializationFeatures)
|
2018-02-11 19:56:52 +01:00
|
|
|
serializationFeatures.foreach {
|
2019-10-02 22:58:11 -04:00
|
|
|
case (feature, value) => objectMapper.configure(feature, value)
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val configuredDeserializationFeatures =
|
2019-06-02 11:27:03 +02:00
|
|
|
features(config, "deserialization-features").map {
|
2018-02-11 19:56:52 +01:00
|
|
|
case (enumName, value) => DeserializationFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val deserializationFeatures =
|
2019-06-02 11:27:03 +02:00
|
|
|
objectMapperFactory.overrideConfiguredDeserializationFeatures(bindingName, configuredDeserializationFeatures)
|
2018-02-11 19:56:52 +01:00
|
|
|
deserializationFeatures.foreach {
|
2019-10-02 22:58:11 -04:00
|
|
|
case (feature, value) => objectMapper.configure(feature, value)
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 05:33:47 -04:00
|
|
|
val configuredMapperFeatures = features(config, "mapper-features").map {
|
|
|
|
|
case (enumName, value) => MapperFeature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val mapperFeatures = objectMapperFactory.overrideConfiguredMapperFeatures(bindingName, configuredMapperFeatures)
|
|
|
|
|
mapperFeatures.foreach {
|
2019-10-02 22:58:11 -04:00
|
|
|
case (feature, value) => objectMapper.configure(feature, value)
|
2019-08-16 05:33:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val configuredJsonParserFeatures = features(config, "json-parser-features").map {
|
|
|
|
|
case (enumName, value) => JsonParser.Feature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val jsonParserFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredJsonParserFeatures(bindingName, configuredJsonParserFeatures)
|
|
|
|
|
jsonParserFeatures.foreach {
|
2019-10-02 22:58:11 -04:00
|
|
|
case (feature, value) => objectMapper.configure(feature, value)
|
2019-08-16 05:33:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val configuredJsonGeneratorFeatures = features(config, "json-generator-features").map {
|
|
|
|
|
case (enumName, value) => JsonGenerator.Feature.valueOf(enumName) -> value
|
|
|
|
|
}
|
|
|
|
|
val jsonGeneratorFeatures =
|
|
|
|
|
objectMapperFactory.overrideConfiguredJsonGeneratorFeatures(bindingName, configuredJsonGeneratorFeatures)
|
|
|
|
|
jsonGeneratorFeatures.foreach {
|
2019-10-02 22:58:11 -04:00
|
|
|
case (feature, value) => objectMapper.configure(feature, value)
|
2019-08-16 05:33:47 -04:00
|
|
|
}
|
2019-10-02 22:58:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def configureObjectMapperModules(
|
|
|
|
|
bindingName: String,
|
|
|
|
|
objectMapper: ObjectMapper,
|
|
|
|
|
objectMapperFactory: JacksonObjectMapperFactory,
|
|
|
|
|
config: Config,
|
|
|
|
|
dynamicAccess: DynamicAccess,
|
|
|
|
|
log: Option[LoggingAdapter]): Unit = {
|
|
|
|
|
|
|
|
|
|
import akka.util.ccompat.JavaConverters._
|
2019-08-16 05:33:47 -04:00
|
|
|
|
2019-06-02 11:27:03 +02:00
|
|
|
val configuredModules = config.getStringList("jackson-modules").asScala
|
2018-02-11 19:56:52 +01:00
|
|
|
val modules1 =
|
2019-07-12 13:31:24 +02:00
|
|
|
configuredModules.flatMap { fqcn =>
|
|
|
|
|
if (isModuleEnabled(fqcn, dynamicAccess)) {
|
|
|
|
|
dynamicAccess.createInstanceFor[Module](fqcn, Nil) match {
|
|
|
|
|
case Success(m) => Some(m)
|
|
|
|
|
case Failure(e) =>
|
|
|
|
|
log.foreach(
|
|
|
|
|
_.error(
|
|
|
|
|
e,
|
|
|
|
|
s"Could not load configured Jackson module [$fqcn], " +
|
|
|
|
|
"please verify classpath dependencies or amend the configuration " +
|
|
|
|
|
"[akka.serialization.jackson-modules]. Continuing without this module."))
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
None
|
|
|
|
|
}
|
2018-02-11 19:56:52 +01:00
|
|
|
|
2019-06-13 16:17:04 +01:00
|
|
|
val modules2 = modules1.map { module =>
|
2018-02-11 19:56:52 +01:00
|
|
|
if (module.isInstanceOf[ParameterNamesModule])
|
|
|
|
|
// ParameterNamesModule needs a special case for the constructor to ensure that single-parameter
|
|
|
|
|
// constructors are handled the same way as constructors with multiple parameters.
|
|
|
|
|
// See https://github.com/FasterXML/jackson-module-parameter-names#delegating-creator
|
|
|
|
|
new ParameterNamesModule(JsonCreator.Mode.PROPERTIES)
|
|
|
|
|
else module
|
|
|
|
|
}.toList
|
|
|
|
|
|
2019-06-02 11:27:03 +02:00
|
|
|
val modules3 = objectMapperFactory.overrideConfiguredModules(bindingName, modules2)
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
modules3.foreach { module =>
|
2019-10-02 22:58:11 -04:00
|
|
|
objectMapper.registerModule(module)
|
2018-02-11 19:56:52 +01:00
|
|
|
log.foreach(_.debug("Registered Jackson module [{}]", module.getClass.getName))
|
|
|
|
|
}
|
2019-10-02 22:58:11 -04:00
|
|
|
}
|
2018-02-11 19:56:52 +01:00
|
|
|
|
2019-10-02 22:58:11 -04:00
|
|
|
/**
|
|
|
|
|
* INTERNAL API: Use [[JacksonObjectMapperProvider#create]]
|
|
|
|
|
*
|
|
|
|
|
* This is needed by one test in Lagom where the ObjectMapper is created without starting and ActorSystem.
|
|
|
|
|
*/
|
|
|
|
|
@InternalStableApi
|
|
|
|
|
def createObjectMapper(
|
|
|
|
|
bindingName: String,
|
|
|
|
|
jsonFactory: Option[JsonFactory],
|
|
|
|
|
objectMapperFactory: JacksonObjectMapperFactory,
|
|
|
|
|
config: Config,
|
|
|
|
|
dynamicAccess: DynamicAccess,
|
|
|
|
|
log: Option[LoggingAdapter]): ObjectMapper = {
|
|
|
|
|
|
|
|
|
|
val configuredJsonFactory = createJsonFactory(bindingName, objectMapperFactory, config, jsonFactory)
|
|
|
|
|
val mapper = objectMapperFactory.newObjectMapper(bindingName, configuredJsonFactory)
|
|
|
|
|
|
|
|
|
|
configureObjectMapperFeatures(bindingName, mapper, objectMapperFactory, config)
|
|
|
|
|
configureObjectMapperModules(bindingName, mapper, objectMapperFactory, config, dynamicAccess, log)
|
|
|
|
|
|
|
|
|
|
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-16 19:11:33 +02:00
|
|
|
private def isModuleEnabled(fqcn: String, dynamicAccess: DynamicAccess): Boolean =
|
|
|
|
|
fqcn match {
|
|
|
|
|
case "akka.serialization.jackson.AkkaTypedJacksonModule" =>
|
|
|
|
|
// akka-actor-typed dependency is "provided" and may not be included
|
|
|
|
|
dynamicAccess.classIsOnClasspath("akka.actor.typed.ActorRef")
|
|
|
|
|
case "akka.serialization.jackson.AkkaStreamJacksonModule" =>
|
|
|
|
|
// akka-stream dependency is "provided" and may not be included
|
|
|
|
|
dynamicAccess.classIsOnClasspath("akka.stream.Graph")
|
|
|
|
|
case _ => true
|
|
|
|
|
}
|
2019-05-29 20:15:46 +02:00
|
|
|
|
2018-02-11 19:56:52 +01:00
|
|
|
private def features(config: Config, section: String): immutable.Seq[(String, Boolean)] = {
|
2019-06-13 16:17:04 +01:00
|
|
|
import akka.util.ccompat.JavaConverters._
|
2018-02-11 19:56:52 +01:00
|
|
|
val cfg = config.getConfig(section)
|
|
|
|
|
cfg.root.keySet().asScala.map(key => key -> cfg.getBoolean(key)).toList
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-12 13:31:24 +02:00
|
|
|
/**
|
|
|
|
|
* Registry of shared `ObjectMapper` instances, each with it's unique `bindingName`.
|
|
|
|
|
*/
|
2018-02-11 19:56:52 +01:00
|
|
|
final class JacksonObjectMapperProvider(system: ExtendedActorSystem) extends Extension {
|
2019-06-02 11:27:03 +02:00
|
|
|
private val objectMappers = new ConcurrentHashMap[String, ObjectMapper]
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
/**
|
2019-07-12 13:31:24 +02:00
|
|
|
* Scala API: Returns an existing Jackson `ObjectMapper` that was created previously with this method, or
|
2018-02-11 19:56:52 +01:00
|
|
|
* creates a new instance.
|
|
|
|
|
*
|
|
|
|
|
* The `ObjectMapper` is created with sensible defaults and modules configured
|
|
|
|
|
* in `akka.serialization.jackson.jackson-modules`. It's using [[JacksonObjectMapperProviderSetup]]
|
|
|
|
|
* if the `ActorSystem` is started with such [[akka.actor.setup.ActorSystemSetup]].
|
|
|
|
|
*
|
2019-07-12 13:31:24 +02:00
|
|
|
* The returned `ObjectMapper` must not be modified, because it may already be in use and such
|
2018-02-11 19:56:52 +01:00
|
|
|
* modifications are not thread-safe.
|
|
|
|
|
*
|
2019-06-02 11:27:03 +02:00
|
|
|
* @param bindingName name of this `ObjectMapper`
|
2019-06-13 17:40:24 +02:00
|
|
|
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON `None` (defaults)
|
2018-02-11 19:56:52 +01:00
|
|
|
* can be used
|
|
|
|
|
*/
|
2019-06-02 11:27:03 +02:00
|
|
|
def getOrCreate(bindingName: String, jsonFactory: Option[JsonFactory]): ObjectMapper = {
|
|
|
|
|
objectMappers.computeIfAbsent(bindingName, _ => create(bindingName, jsonFactory))
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-12 13:31:24 +02:00
|
|
|
/**
|
|
|
|
|
* Java API: Returns an existing Jackson `ObjectMapper` that was created previously with this method, or
|
|
|
|
|
* creates a new instance.
|
|
|
|
|
*
|
|
|
|
|
* The `ObjectMapper` is created with sensible defaults and modules configured
|
|
|
|
|
* in `akka.serialization.jackson.jackson-modules`. It's using [[JacksonObjectMapperProviderSetup]]
|
|
|
|
|
* if the `ActorSystem` is started with such [[akka.actor.setup.ActorSystemSetup]].
|
|
|
|
|
*
|
|
|
|
|
* The returned `ObjectMapper` must not be modified, because it may already be in use and such
|
|
|
|
|
* modifications are not thread-safe.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON `None` (defaults)
|
|
|
|
|
* can be used
|
|
|
|
|
*/
|
|
|
|
|
def getOrCreate(bindingName: String, jsonFactory: Optional[JsonFactory]): ObjectMapper =
|
|
|
|
|
getOrCreate(bindingName, jsonFactory.asScala)
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
/**
|
2019-07-12 13:31:24 +02:00
|
|
|
* Scala API: Creates a new instance of a Jackson `ObjectMapper` with sensible defaults and modules configured
|
2018-02-11 19:56:52 +01:00
|
|
|
* in `akka.serialization.jackson.jackson-modules`. It's using [[JacksonObjectMapperProviderSetup]]
|
|
|
|
|
* if the `ActorSystem` is started with such [[akka.actor.setup.ActorSystemSetup]].
|
|
|
|
|
*
|
2019-06-02 11:27:03 +02:00
|
|
|
* @param bindingName name of this `ObjectMapper`
|
2019-06-13 17:40:24 +02:00
|
|
|
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON `None` (defaults)
|
2018-02-11 19:56:52 +01:00
|
|
|
* can be used
|
|
|
|
|
* @see [[JacksonObjectMapperProvider#getOrCreate]]
|
|
|
|
|
*/
|
2019-06-02 11:27:03 +02:00
|
|
|
def create(bindingName: String, jsonFactory: Option[JsonFactory]): ObjectMapper = {
|
2018-02-11 19:56:52 +01:00
|
|
|
val log = Logging.getLogger(system, JacksonObjectMapperProvider.getClass)
|
|
|
|
|
val dynamicAccess = system.dynamicAccess
|
|
|
|
|
|
2019-06-02 11:27:03 +02:00
|
|
|
val config = JacksonObjectMapperProvider.configForBinding(bindingName, system.settings.config)
|
|
|
|
|
|
2018-02-11 19:56:52 +01:00
|
|
|
val factory = system.settings.setup.get[JacksonObjectMapperProviderSetup] match {
|
|
|
|
|
case Some(setup) => setup.factory
|
|
|
|
|
case None => new JacksonObjectMapperFactory // default
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-02 11:27:03 +02:00
|
|
|
JacksonObjectMapperProvider.createObjectMapper(bindingName, jsonFactory, factory, config, dynamicAccess, Some(log))
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-12 13:31:24 +02:00
|
|
|
/**
|
|
|
|
|
* Java API: Creates a new instance of a Jackson `ObjectMapper` with sensible defaults and modules configured
|
|
|
|
|
* in `akka.serialization.jackson.jackson-modules`. It's using [[JacksonObjectMapperProviderSetup]]
|
|
|
|
|
* if the `ActorSystem` is started with such [[akka.actor.setup.ActorSystemSetup]].
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON `None` (defaults)
|
|
|
|
|
* can be used
|
|
|
|
|
* @see [[JacksonObjectMapperProvider#getOrCreate]]
|
|
|
|
|
*/
|
|
|
|
|
def create(bindingName: String, jsonFactory: Optional[JsonFactory]): ObjectMapper =
|
|
|
|
|
create(bindingName, jsonFactory.asScala)
|
|
|
|
|
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object JacksonObjectMapperProviderSetup {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Scala API: factory for defining a `JacksonObjectMapperProvider` that is passed in when ActorSystem
|
|
|
|
|
* is created rather than creating one from configured class name.
|
|
|
|
|
*/
|
|
|
|
|
def apply(factory: JacksonObjectMapperFactory): JacksonObjectMapperProviderSetup =
|
|
|
|
|
new JacksonObjectMapperProviderSetup(factory)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Java API: factory for defining a `JacksonObjectMapperProvider` that is passed in when ActorSystem
|
|
|
|
|
* is created rather than creating one from configured class name.
|
|
|
|
|
*/
|
|
|
|
|
def create(factory: JacksonObjectMapperFactory): JacksonObjectMapperProviderSetup =
|
|
|
|
|
apply(factory)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup for defining a `JacksonObjectMapperProvider` that can be passed in when ActorSystem
|
|
|
|
|
* is created rather than creating one from configured class name. Create a subclass of
|
|
|
|
|
* [[JacksonObjectMapperFactory]] and override the methods to amend the defaults.
|
|
|
|
|
*/
|
|
|
|
|
final class JacksonObjectMapperProviderSetup(val factory: JacksonObjectMapperFactory) extends Setup
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Used with [[JacksonObjectMapperProviderSetup]] for defining a `JacksonObjectMapperProvider` that can be
|
|
|
|
|
* passed in when ActorSystem is created rather than creating one from configured class name.
|
|
|
|
|
* Create a subclass and override the methods to amend the defaults.
|
|
|
|
|
*/
|
|
|
|
|
class JacksonObjectMapperFactory {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Override this method to create a new custom instance of `ObjectMapper` for the given `serializerIdentifier`.
|
|
|
|
|
*
|
2019-06-02 11:27:03 +02:00
|
|
|
* @param bindingName name of this `ObjectMapper`
|
2019-06-13 17:40:24 +02:00
|
|
|
* @param jsonFactory optional `JsonFactory` such as `CBORFactory`, for plain JSON `None` (defaults)
|
2018-02-11 19:56:52 +01:00
|
|
|
* can be used
|
|
|
|
|
*/
|
2019-10-02 22:58:11 -04:00
|
|
|
def newObjectMapper(@unused bindingName: String, jsonFactory: JsonFactory): ObjectMapper =
|
|
|
|
|
JsonMapper.builder(jsonFactory).build()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured modules are added to
|
|
|
|
|
* the mapper. These modules can be amended programatically by overriding this method and
|
|
|
|
|
* return the modules that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
|
|
|
|
* When implementing a `JacksonObjectMapperFactory` with Java the `immutable.Seq` can be
|
|
|
|
|
* created with [[akka.japi.Util.immutableSeq]].
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredModules the list of `Modules` that were configured in
|
|
|
|
|
* `akka.serialization.jackson.deserialization-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredModules(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredModules: immutable.Seq[Module]): immutable.Seq[Module] =
|
|
|
|
|
configuredModules
|
2018-02-11 19:56:52 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured serialization features are applied to
|
|
|
|
|
* the mapper. These features can be amended programatically by overriding this method and
|
|
|
|
|
* return the features that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
2019-07-12 13:31:24 +02:00
|
|
|
* When implementing a `JacksonObjectMapperFactory` with Java the `immutable.Seq` can be
|
|
|
|
|
* created with [[akka.japi.Util.immutableSeq]].
|
|
|
|
|
*
|
2019-06-02 11:27:03 +02:00
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
2018-02-11 19:56:52 +01:00
|
|
|
* @param configuredFeatures the list of `SerializationFeature` that were configured in
|
|
|
|
|
* `akka.serialization.jackson.serialization-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredSerializationFeatures(
|
2019-06-02 11:27:03 +02:00
|
|
|
@unused bindingName: String,
|
2018-02-11 19:56:52 +01:00
|
|
|
configuredFeatures: immutable.Seq[(SerializationFeature, Boolean)])
|
|
|
|
|
: immutable.Seq[(SerializationFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured deserialization features are applied to
|
|
|
|
|
* the mapper. These features can be amended programatically by overriding this method and
|
|
|
|
|
* return the features that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
2019-07-12 13:31:24 +02:00
|
|
|
* When implementing a `JacksonObjectMapperFactory` with Java the `immutable.Seq` can be
|
|
|
|
|
* created with [[akka.japi.Util.immutableSeq]].
|
|
|
|
|
*
|
2019-06-02 11:27:03 +02:00
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
2018-02-11 19:56:52 +01:00
|
|
|
* @param configuredFeatures the list of `DeserializationFeature` that were configured in
|
|
|
|
|
* `akka.serialization.jackson.deserialization-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredDeserializationFeatures(
|
2019-06-02 11:27:03 +02:00
|
|
|
@unused bindingName: String,
|
2018-02-11 19:56:52 +01:00
|
|
|
configuredFeatures: immutable.Seq[(DeserializationFeature, Boolean)])
|
|
|
|
|
: immutable.Seq[(DeserializationFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
2019-08-16 05:33:47 -04:00
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured mapper features are applied to
|
|
|
|
|
* the mapper. These features can be amended programmatically by overriding this method and
|
|
|
|
|
* return the features that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `MapperFeatures` that were configured in `akka.serialization.jackson.mapper-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredMapperFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(MapperFeature, Boolean)]): immutable.Seq[(MapperFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured JSON parser features are applied to
|
|
|
|
|
* the mapper. These features can be amended programmatically by overriding this method and
|
|
|
|
|
* return the features that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `JsonParser.Feature` that were configured in `akka.serialization.jackson.json-parser-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredJsonParserFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(JsonParser.Feature, Boolean)]): immutable.Seq[(JsonParser.Feature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* After construction of the `ObjectMapper` the configured JSON generator features are applied to
|
|
|
|
|
* the mapper. These features can be amended programmatically by overriding this method and
|
|
|
|
|
* return the features that are to be applied to the `ObjectMapper`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `JsonGenerator.Feature` that were configured in `akka.serialization.jackson.json-generator-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredJsonGeneratorFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(JsonGenerator.Feature, Boolean)])
|
|
|
|
|
: immutable.Seq[(JsonGenerator.Feature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
2019-10-02 22:58:11 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* `StreamReadFeature`s used to configure the `JsonFactoryBuilder` that, if provided, will later be used to create
|
|
|
|
|
* an `ObjectMapper`. These features can be amended programmatically by overriding this method and return the features
|
|
|
|
|
* that are to be applied to the `JsonFactoryBuilder`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `StreamReadFeature` that were configured in `akka.serialization.jackson.stream-read-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredStreamReadFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(StreamReadFeature, Boolean)]): immutable.Seq[(StreamReadFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* `StreamWriteFeature`s used to configure the `JsonFactoryBuilder` that, if provided, will later be used to create
|
|
|
|
|
* an `ObjectMapper`. These features can be amended programmatically by overriding this method and return the features
|
|
|
|
|
* that are to be applied to the `JsonFactoryBuilder`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `StreamWriterFeature` that were configured in `akka.serialization.jackson.stream-write-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredStreamWriteFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(StreamWriteFeature, Boolean)]): immutable.Seq[(StreamWriteFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* `JsonReadFeature`s used to configure the `JsonFactoryBuilder` that, if provided, will later be used to create
|
|
|
|
|
* an `ObjectMapper`. These features can be amended programmatically by overriding this method and return the features
|
|
|
|
|
* that are to be applied to the `JsonFactoryBuilder`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `JsonReadFeature` that were configured in `akka.serialization.jackson.json-read-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredJsonReadFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(JsonReadFeature, Boolean)]): immutable.Seq[(JsonReadFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* `JsonWriteFeature`s used to configure the `JsonFactoryBuilder` that, if provided, will later be used to create
|
|
|
|
|
* an `ObjectMapper`. These features can be amended programmatically by overriding this method and return the features
|
|
|
|
|
* that are to be applied to the `JsonFactoryBuilder`.
|
|
|
|
|
*
|
|
|
|
|
* @param bindingName bindingName name of this `ObjectMapper`
|
|
|
|
|
* @param configuredFeatures the list of `JsonWriteFeature` that were configured in `akka.serialization.jackson.json-write-features`
|
|
|
|
|
*/
|
|
|
|
|
def overrideConfiguredJsonWriteFeatures(
|
|
|
|
|
@unused bindingName: String,
|
|
|
|
|
configuredFeatures: immutable.Seq[(JsonWriteFeature, Boolean)]): immutable.Seq[(JsonWriteFeature, Boolean)] =
|
|
|
|
|
configuredFeatures
|
2018-02-11 19:56:52 +01:00
|
|
|
}
|