From dad79bbb9ddc34ad3720bea221c02a064ac55218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C5=A0lahora?= Date: Thu, 3 Nov 2022 08:57:00 +0100 Subject: [PATCH] Added possibility to customize `ObjectMapper`'s `KotlinModule` --- .../kmongo/jackson/ObjectMapperFactory.kt | 9 +++++---- .../litote/kmongo/util/KMongoConfiguration.kt | 16 +++++++++++++++- .../kmongo/jackson/ObjectMapperFactoryTest.kt | 17 +++++++++++++++++ kmongo-kdoc/docs/object-mapping.md | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/jackson/ObjectMapperFactory.kt b/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/jackson/ObjectMapperFactory.kt index 51e3b30a..cc5ed507 100644 --- a/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/jackson/ObjectMapperFactory.kt +++ b/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/jackson/ObjectMapperFactory.kt @@ -28,13 +28,15 @@ import com.fasterxml.jackson.databind.MapperFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.kotlinModule import com.mongodb.BasicDBObject import com.mongodb.DBObject import com.mongodb.DBRef import org.bson.UuidRepresentation import org.bson.types.ObjectId import org.litote.jackson.registerModulesFromServiceLoader +import org.litote.kmongo.util.KotlinModuleConfiguration import org.litote.kmongo.util.ObjectMappingConfiguration import java.math.BigDecimal import java.math.BigInteger @@ -49,7 +51,7 @@ internal object ObjectMapperFactory { fun createExtendedJsonObjectMapper(): ObjectMapper { return ObjectMapper() - .registerKotlinModule() + .registerModule(kotlinModule(KotlinModuleConfiguration.kotlinModuleInitializer)) .registerModule(SetMappingModule()) .registerModule(ExtendedJsonModule()) .configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true) @@ -67,7 +69,7 @@ internal object ObjectMapperFactory { private fun configureBson(mapper: ObjectMapper, uuidRepresentation: UuidRepresentation?): ObjectMapper { return mapper.registerModule(de.undercouch.bson4jackson.BsonModule()) - .registerKotlinModule() + .registerModule(kotlinModule(KotlinModuleConfiguration.kotlinModuleInitializer)) .registerModule(CustomJacksonModule) .registerModule(SetMappingModule()) .registerModule(BsonModule(uuidRepresentation)) @@ -81,7 +83,6 @@ internal object ObjectMapperFactory { fun createFilterIdObjectMapper(objectMapper: ObjectMapper): ObjectMapper { return objectMapper.copy().registerModule(FilterIdModule()) } - } private object CustomJacksonModule : SimpleModule() { diff --git a/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/util/KMongoConfiguration.kt b/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/util/KMongoConfiguration.kt index 00695483..96d02d36 100644 --- a/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/util/KMongoConfiguration.kt +++ b/kmongo-jackson-mapping/src/main/kotlin/org/litote/kmongo/util/KMongoConfiguration.kt @@ -20,10 +20,11 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include.ALWAYS import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL import com.fasterxml.jackson.databind.Module import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule import org.bson.UuidRepresentation import org.litote.kmongo.jackson.JacksonCodecProvider import org.litote.kmongo.jackson.ObjectMapperFactory -import kotlin.LazyThreadSafetyMode.PUBLICATION +import org.litote.kmongo.util.KotlinModuleConfiguration.kotlinModuleInitializer /** * Configure the jackson mapper engine. @@ -41,6 +42,19 @@ object KMongoJacksonFeature { } } +/** + * Configure the [KotlinModule] used by jackson mapper engine. + * + * Call the methods of this object *before* any call to [KMongoConfiguration] methods. + */ +object KotlinModuleConfiguration { + + /** + * Function to customize [KotlinModule] used by KMongo. + */ + var kotlinModuleInitializer: KotlinModule.Builder.() -> Unit = { } +} + /** * Use this class to customize the default behaviour of KMongo jackson bindings. */ diff --git a/kmongo-jackson-mapping/src/test/kotlin/org/litote/kmongo/jackson/ObjectMapperFactoryTest.kt b/kmongo-jackson-mapping/src/test/kotlin/org/litote/kmongo/jackson/ObjectMapperFactoryTest.kt index c76baa77..2f480344 100644 --- a/kmongo-jackson-mapping/src/test/kotlin/org/litote/kmongo/jackson/ObjectMapperFactoryTest.kt +++ b/kmongo-jackson-mapping/src/test/kotlin/org/litote/kmongo/jackson/ObjectMapperFactoryTest.kt @@ -16,9 +16,11 @@ package org.litote.kmongo.jackson +import com.fasterxml.jackson.module.kotlin.KotlinFeature import com.fasterxml.jackson.module.kotlin.readValue import org.junit.Test import org.litote.kmongo.util.KMongoConfiguration +import org.litote.kmongo.util.KotlinModuleConfiguration import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -29,6 +31,7 @@ class ObjectMapperFactoryTest { data class T(val set:Set, val mutableSet: MutableSet) data class M(val map:Map, val mutableMap: MutableMap) + object Singleton @Test fun `Set is deserialized as LinkedHashSet`() { @@ -45,4 +48,18 @@ class ObjectMapperFactoryTest { assertTrue { m.map is LinkedHashMap } assertTrue { m.mutableMap is LinkedHashMap } } + + @Test + fun `Deserialized object is the same instance as serialized object`() { + try { + KotlinModuleConfiguration.kotlinModuleInitializer = { enable(KotlinFeature.SingletonSupport) } + KMongoConfiguration.resetConfiguration() + val m = KMongoConfiguration.extendedJsonMapper.writeValueAsString(Singleton) + val deserializedSingleton = KMongoConfiguration.extendedJsonMapper.readValue(m) + assertTrue { Singleton === deserializedSingleton } + } finally { + KotlinModuleConfiguration.kotlinModuleInitializer = { } + KMongoConfiguration.resetConfiguration() + } + } } \ No newline at end of file diff --git a/kmongo-kdoc/docs/object-mapping.md b/kmongo-kdoc/docs/object-mapping.md index cd021e93..74b30cee 100644 --- a/kmongo-kdoc/docs/object-mapping.md +++ b/kmongo-kdoc/docs/object-mapping.md @@ -5,6 +5,22 @@ Query results are automatically mapped to objects. Look at the [Quick Start related paragraph](https://litote.org/kmongo/quick-start/#object-mapping-engine) in order to know how to select the object mapping engine. +## Configure ```KotlinModule``` + +The ```ObjectMapper``` used by KMongo uses a [jackson's KotlinModule](https://github.com/FasterXML/jackson-module-kotlin). +The module is created with default ```KotlinFeature```s. +To change configuration of the module, use ```KotlinModuleConfiguration``` object: + +```kotlin +KotlinModuleConfiguration.kotlinModuleInitializer = { + // Configure `KotlinModule` using its `Builder` (which is referenced as `this`): + enable(KotlinFeature.SingletonSupport) + enable(KotlinFeature.StrictNullChecks) + ... +} +KMongoConfiguration.resetConfiguration() +``` + ## Set your _id To manage Mongo ```_id```, a class must have one ```_id``` property