From 44d34e89ae5e9022391356e3922c5f8532a2f310 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sat, 7 Mar 2020 11:32:30 -0500 Subject: [PATCH 01/11] Add Builder for module --- .../jackson/module/kotlin/KotlinModule.kt | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index 2832bb5e..ebb479ca 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -16,7 +16,6 @@ class KotlinModule constructor ( val nullToEmptyMap: Boolean = false, val nullisSameAsDefault: Boolean = false ) : SimpleModule(PackageVersion.VERSION) { - @Deprecated(level = DeprecationLevel.HIDDEN, message = "For ABI compatibility") constructor( reflectionCacheSize: Int = 512, @@ -60,6 +59,37 @@ class KotlinModule constructor ( addMixIn(LongRange::class.java, ClosedRangeMixin::class.java) addMixIn(ClosedRange::class.java, ClosedRangeMixin::class.java) } + + private constructor(builder: Builder) : this( + builder.reflectionCacheSize, + builder.nullToEmptyCollection, + builder.nullToEmptyMap, + builder.nullisSameAsDefault + ) + + class Builder { + var reflectionCacheSize: Int = 512 + private set + + var nullToEmptyCollection: Boolean = false + private set + + var nullToEmptyMap: Boolean = false + private set + + var nullisSameAsDefault: Boolean = false + private set + + fun reflectionCacheSize(reflectionCacheSize: Int) = apply { this.reflectionCacheSize = reflectionCacheSize } + + fun nullToEmptyCollection(nullToEmptyCollection: Boolean) = apply { this.nullToEmptyCollection = nullToEmptyCollection } + + fun nullToEmptyMap(nullToEmptyMap: Boolean) = apply { this.nullToEmptyMap = nullToEmptyMap } + + fun nullisSameAsDefault(nullisSameAsDefault: Boolean) = apply { this.nullisSameAsDefault = nullisSameAsDefault } + + fun build() = KotlinModule(this) + } } From 733a70fcebc0dfb86f27e7637110f15780500076 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 10:50:50 -0600 Subject: [PATCH 02/11] Test builder; correct camel case for nullIsSameAsDefault --- .../jackson/module/kotlin/KotlinModule.kt | 24 +++---- .../jackson/module/kotlin/KotlinModuleTest.kt | 67 +++++++++++++++++++ .../module/kotlin/test/NullToDefaultTests.kt | 7 +- 3 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index ebb479ca..7c4a917f 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -14,7 +14,7 @@ class KotlinModule constructor ( val reflectionCacheSize: Int = 512, val nullToEmptyCollection: Boolean = false, val nullToEmptyMap: Boolean = false, - val nullisSameAsDefault: Boolean = false + val nullIsSameAsDefault: Boolean = false ) : SimpleModule(PackageVersion.VERSION) { @Deprecated(level = DeprecationLevel.HIDDEN, message = "For ABI compatibility") constructor( @@ -23,6 +23,13 @@ class KotlinModule constructor ( nullToEmptyMap: Boolean = false ) : this(reflectionCacheSize, nullToEmptyCollection, nullToEmptyMap, false) + private constructor(builder: Builder) : this( + builder.reflectionCacheSize, + builder.nullToEmptyCollection, + builder.nullToEmptyMap, + builder.nullIsSameAsDefault + ) + companion object { const val serialVersionUID = 1L } @@ -38,12 +45,12 @@ class KotlinModule constructor ( val cache = ReflectionCache(reflectionCacheSize) - context.addValueInstantiators(KotlinInstantiators(cache, nullToEmptyCollection, nullToEmptyMap, nullisSameAsDefault)) + context.addValueInstantiators(KotlinInstantiators(cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) // [module-kotlin#225]: keep Kotlin singletons as singletons context.addBeanDeserializerModifier(KotlinBeanDeserializerModifier) - context.insertAnnotationIntrospector(KotlinAnnotationIntrospector(context, cache, nullToEmptyCollection, nullToEmptyMap, nullisSameAsDefault)) + context.insertAnnotationIntrospector(KotlinAnnotationIntrospector(context, cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) context.appendAnnotationIntrospector(KotlinNamesAnnotationIntrospector(this, cache, ignoredClassesForImplyingJsonCreator)) context.addDeserializers(KotlinDeserializers()) @@ -60,13 +67,6 @@ class KotlinModule constructor ( addMixIn(ClosedRange::class.java, ClosedRangeMixin::class.java) } - private constructor(builder: Builder) : this( - builder.reflectionCacheSize, - builder.nullToEmptyCollection, - builder.nullToEmptyMap, - builder.nullisSameAsDefault - ) - class Builder { var reflectionCacheSize: Int = 512 private set @@ -77,7 +77,7 @@ class KotlinModule constructor ( var nullToEmptyMap: Boolean = false private set - var nullisSameAsDefault: Boolean = false + var nullIsSameAsDefault: Boolean = false private set fun reflectionCacheSize(reflectionCacheSize: Int) = apply { this.reflectionCacheSize = reflectionCacheSize } @@ -86,7 +86,7 @@ class KotlinModule constructor ( fun nullToEmptyMap(nullToEmptyMap: Boolean) = apply { this.nullToEmptyMap = nullToEmptyMap } - fun nullisSameAsDefault(nullisSameAsDefault: Boolean) = apply { this.nullisSameAsDefault = nullisSameAsDefault } + fun nullIsSameAsDefault(nullIsSameAsDefault: Boolean) = apply { this.nullIsSameAsDefault = nullIsSameAsDefault } fun build() = KotlinModule(this) } diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt new file mode 100644 index 00000000..daf926ce --- /dev/null +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt @@ -0,0 +1,67 @@ +package com.fasterxml.jackson.module.kotlin + +import org.junit.Assert.* +import org.junit.Test + +class KotlinModuleTest { + @Test + fun builder_Defaults() { + val module = KotlinModule.Builder().build() + + assertEquals(512, module.reflectionCacheSize) + assertFalse(module.nullToEmptyCollection) + assertFalse(module.nullToEmptyMap) + assertFalse(module.nullIsSameAsDefault) + } + + @Test + fun builder_SetAll() { + val module = KotlinModule.Builder().apply { + reflectionCacheSize(123) + nullToEmptyCollection(true) + nullToEmptyMap(true) + nullIsSameAsDefault(true) + }.build() + + assertEquals(123, module.reflectionCacheSize) + assertTrue(module.nullToEmptyCollection) + assertTrue(module.nullToEmptyMap) + assertTrue(module.nullIsSameAsDefault) + } + + @Test + fun builder_NullToEmptyCollection() { + val module = KotlinModule.Builder().apply { + nullToEmptyCollection(true) + }.build() + + assertEquals(512, module.reflectionCacheSize) + assertTrue(module.nullToEmptyCollection) + assertFalse(module.nullToEmptyMap) + assertFalse(module.nullIsSameAsDefault) + } + + @Test + fun builder_NullToEmptyMap() { + val module = KotlinModule.Builder().apply { + nullToEmptyMap(true) + }.build() + + assertEquals(512, module.reflectionCacheSize) + assertFalse(module.nullToEmptyCollection) + assertTrue(module.nullToEmptyMap) + assertFalse(module.nullIsSameAsDefault) + } + + @Test + fun builder_NullIsSameAsDefault() { + val module = KotlinModule.Builder().apply { + nullIsSameAsDefault(true) + }.build() + + assertEquals(512, module.reflectionCacheSize) + assertFalse(module.nullToEmptyCollection) + assertFalse(module.nullToEmptyMap) + assertTrue(module.nullIsSameAsDefault) + } +} diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/NullToDefaultTests.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/NullToDefaultTests.kt index 50a17852..628ea5e6 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/NullToDefaultTests.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/NullToDefaultTests.kt @@ -3,16 +3,13 @@ package com.fasterxml.jackson.module.kotlin.test import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import org.junit.Assert -import org.junit.Ignore import org.junit.Test -import org.junit.internal.runners.statements.ExpectException class TestNullToDefault { - private fun createMapper(allowDefaultingByNull: Boolean) = ObjectMapper().registerModule(KotlinModule(nullisSameAsDefault = allowDefaultingByNull)) + private fun createMapper(allowDefaultingByNull: Boolean) = ObjectMapper().registerModule(KotlinModule(nullIsSameAsDefault = allowDefaultingByNull)) private data class TestClass(val sku: Int = -1, val text: String, @@ -81,4 +78,4 @@ class TestNullToDefault { Assert.assertTrue(item.name != null) Assert.assertTrue(item.order == -1) } -} \ No newline at end of file +} From e0c4fd55a9627719ab94e4c24525e1bf675c7b93 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 14:10:04 -0600 Subject: [PATCH 03/11] Update test for offset change in databind #2643 --- .../jackson/module/kotlin/test/ParameterNameTests.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ParameterNameTests.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ParameterNameTests.kt index 1ff0a6e6..52b15410 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ParameterNameTests.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ParameterNameTests.kt @@ -36,8 +36,8 @@ class TestJacksonWithKotlin { } } - private val normalCasedJson = """{"name":"Frank","age":30,"primaryAddress":"something here","renamed":true,"createdDt":"2016-10-25T18:25:48.000+0000"}""" - private val pascalCasedJson = """{"Name":"Frank","Age":30,"PrimaryAddress":"something here","Renamed":true,"CreatedDt":"2016-10-25T18:25:48.000+0000"}""" + private val normalCasedJson = """{"name":"Frank","age":30,"primaryAddress":"something here","renamed":true,"createdDt":"2016-10-25T18:25:48.000+00:00"}""" + private val pascalCasedJson = """{"Name":"Frank","Age":30,"PrimaryAddress":"something here","Renamed":true,"CreatedDt":"2016-10-25T18:25:48.000+00:00"}""" private val normalCasedMapper = jacksonObjectMapper() .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) From a1142dc7d8113a3b26cb1b54963cb33570ba8be4 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 14:13:12 -0600 Subject: [PATCH 04/11] Describe change in version file --- release-notes/VERSION-2.x | 1 + 1 file changed, 1 insertion(+) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 8c261afc..3ae95b0e 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -7,6 +7,7 @@ Project: jackson-module-kotlin 2.11.0 (not yet released) #284: Use `AnnotationIntrospector.findRenameByField()` to support "is properties" +- Add Builder for KotlinModule Kotlin updated to 1.3.61 From c011073e0a881a845d0bb64275ec5758f45b0750 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 12:56:43 -0600 Subject: [PATCH 05/11] Add setting for experimental singleton support --- .../jackson/module/kotlin/KotlinModule.kt | 15 ++++++-- .../jackson/module/kotlin/KotlinModuleTest.kt | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index 7c4a917f..32e1d264 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -14,7 +14,8 @@ class KotlinModule constructor ( val reflectionCacheSize: Int = 512, val nullToEmptyCollection: Boolean = false, val nullToEmptyMap: Boolean = false, - val nullIsSameAsDefault: Boolean = false + val nullIsSameAsDefault: Boolean = false, + val enableExperimentalSingletonSupport: Boolean = false ) : SimpleModule(PackageVersion.VERSION) { @Deprecated(level = DeprecationLevel.HIDDEN, message = "For ABI compatibility") constructor( @@ -27,7 +28,8 @@ class KotlinModule constructor ( builder.reflectionCacheSize, builder.nullToEmptyCollection, builder.nullToEmptyMap, - builder.nullIsSameAsDefault + builder.nullIsSameAsDefault, + builder.enableExperimentalSingletonSupport ) companion object { @@ -80,14 +82,21 @@ class KotlinModule constructor ( var nullIsSameAsDefault: Boolean = false private set + var enableExperimentalSingletonSupport = false + private set + fun reflectionCacheSize(reflectionCacheSize: Int) = apply { this.reflectionCacheSize = reflectionCacheSize } - fun nullToEmptyCollection(nullToEmptyCollection: Boolean) = apply { this.nullToEmptyCollection = nullToEmptyCollection } + fun nullToEmptyCollection(nullToEmptyCollection: Boolean) = + apply { this.nullToEmptyCollection = nullToEmptyCollection } fun nullToEmptyMap(nullToEmptyMap: Boolean) = apply { this.nullToEmptyMap = nullToEmptyMap } fun nullIsSameAsDefault(nullIsSameAsDefault: Boolean) = apply { this.nullIsSameAsDefault = nullIsSameAsDefault } + fun enableExperimentalSingletonSupport(enableExperimentalSingletonSupport: Boolean) = + apply { this.enableExperimentalSingletonSupport = enableExperimentalSingletonSupport } + fun build() = KotlinModule(this) } } diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt index daf926ce..6212a9ba 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt @@ -2,8 +2,27 @@ package com.fasterxml.jackson.module.kotlin import org.junit.Assert.* import org.junit.Test +import kotlin.reflect.full.memberProperties +import kotlin.reflect.full.primaryConstructor class KotlinModuleTest { + /** + * Ensure that the main constructor and the Builder have the same default settings. + */ + @Test + fun constructorAndBuilderCreateSameDefaultObject() { + val constructorModule = KotlinModule() + val builderModule = KotlinModule.Builder().build() + + + assertEquals(KotlinModule::class.primaryConstructor?.parameters?.size, KotlinModule.Builder::class.memberProperties.size) + assertEquals(constructorModule.reflectionCacheSize, builderModule.reflectionCacheSize) + assertEquals(constructorModule.nullToEmptyCollection, builderModule.nullToEmptyCollection) + assertEquals(constructorModule.nullToEmptyMap, builderModule.nullToEmptyMap) + assertEquals(constructorModule.nullIsSameAsDefault, builderModule.nullIsSameAsDefault) + assertEquals(constructorModule.enableExperimentalSingletonSupport, builderModule.enableExperimentalSingletonSupport) + } + @Test fun builder_Defaults() { val module = KotlinModule.Builder().build() @@ -12,6 +31,7 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) + assertFalse(module.enableExperimentalSingletonSupport) } @Test @@ -21,12 +41,14 @@ class KotlinModuleTest { nullToEmptyCollection(true) nullToEmptyMap(true) nullIsSameAsDefault(true) + enableExperimentalSingletonSupport(true) }.build() assertEquals(123, module.reflectionCacheSize) assertTrue(module.nullToEmptyCollection) assertTrue(module.nullToEmptyMap) assertTrue(module.nullIsSameAsDefault) + assertTrue(module.enableExperimentalSingletonSupport) } @Test @@ -39,6 +61,7 @@ class KotlinModuleTest { assertTrue(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) + assertFalse(module.enableExperimentalSingletonSupport) } @Test @@ -51,6 +74,7 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertTrue(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) + assertFalse(module.enableExperimentalSingletonSupport) } @Test @@ -63,5 +87,19 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertTrue(module.nullIsSameAsDefault) + assertFalse(module.enableExperimentalSingletonSupport) + } + + @Test + fun builder_EnableExperimentalSingletonSupport() { + val module = KotlinModule.Builder().apply { + enableExperimentalSingletonSupport(true) + }.build() + + assertEquals(512, module.reflectionCacheSize) + assertFalse(module.nullToEmptyCollection) + assertFalse(module.nullToEmptyMap) + assertFalse(module.nullIsSameAsDefault) + assertTrue(module.enableExperimentalSingletonSupport) } } From 228364519e42b3445d7ad65c8149d705eabd4ab3 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 13:10:55 -0600 Subject: [PATCH 06/11] Conditinoally enable experimental singleton support --- .../com/fasterxml/jackson/module/kotlin/KotlinModule.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index 32e1d264..15c3d202 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -49,8 +49,10 @@ class KotlinModule constructor ( context.addValueInstantiators(KotlinInstantiators(cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) - // [module-kotlin#225]: keep Kotlin singletons as singletons - context.addBeanDeserializerModifier(KotlinBeanDeserializerModifier) + if (enableExperimentalSingletonSupport) { + // [jackson-module-kotlin#225]: keep Kotlin singletons as singletons + context.addBeanDeserializerModifier(KotlinBeanDeserializerModifier) + } context.insertAnnotationIntrospector(KotlinAnnotationIntrospector(context, cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) context.appendAnnotationIntrospector(KotlinNamesAnnotationIntrospector(this, cache, ignoredClassesForImplyingJsonCreator)) From 3cfa45deb14be96ae2f70d38e05760fefaf43e8e Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 14:26:02 -0600 Subject: [PATCH 07/11] Update credits & version --- release-notes/CREDITS-2.x | 5 +++++ release-notes/VERSION-2.x | 2 ++ 2 files changed, 7 insertions(+) diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index f5cefc91..f4cf3c66 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -36,3 +36,8 @@ Vladimir Petrakovich (frost13it@github) * Contributed fix for #279: 2.10 introduces another binary compatibility issue in `KotlinModule` constructor (2.10.2) + +Drew Stephens (dinomite@github) +* Contributed fix for #281: KotlinObjectSingletonDeserializer fails to deserialize + previously serialized JSON as it doesn't delegate deserializeWithType + (2.11.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 3ae95b0e..8bd08940 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -8,6 +8,8 @@ Project: jackson-module-kotlin #284: Use `AnnotationIntrospector.findRenameByField()` to support "is properties" - Add Builder for KotlinModule +#281: Hide singleton deserialization support behind a setting on the module, + `enableExperimentalSingletonSupport` Kotlin updated to 1.3.61 From 21de487dd6180122dca29dd4ca00beba53467699 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Sun, 8 Mar 2020 15:30:51 -0600 Subject: [PATCH 08/11] Update test for singleton support --- .../module/kotlin/test/ObjectSingletonTest.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt index 8b0e5f97..dda9cc8d 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt @@ -1,18 +1,16 @@ package com.fasterxml.jackson.module.kotlin.test import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.readValue import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.not import org.hamcrest.MatcherAssert.assertThat import org.junit.Test // [module-kotlin#225]: keep Kotlin singletons as singletons class TestObjectSingleton { - - val mapper: ObjectMapper = jacksonObjectMapper() + val mapper: ObjectMapper = ObjectMapper() + .registerModule(KotlinModule(enableExperimentalSingletonSupport = true)) object Singleton { var content = 1 // mutable state @@ -49,9 +47,8 @@ class TestObjectSingleton { val newSingleton = mapper.readValue(js) assertThat(newSingleton.content, equalTo(Singleton.content)) - newSingleton.content += 1; + newSingleton.content += 1 assertThat(Singleton.content, equalTo(newSingleton.content)) } - -} \ No newline at end of file +} From f19a736a5392b7a07498f27c3cdfe876273675f4 Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Wed, 11 Mar 2020 14:57:07 -0600 Subject: [PATCH 09/11] Use enum for singleton support configuration --- .../jackson/module/kotlin/KotlinModule.kt | 16 ++++++++++------ .../jackson/module/kotlin/SingletonSupport.kt | 12 ++++++++++++ .../jackson/module/kotlin/KotlinModuleTest.kt | 17 +++++++---------- .../module/kotlin/test/ObjectSingletonTest.kt | 4 +++- 4 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 src/main/kotlin/com/fasterxml/jackson/module/kotlin/SingletonSupport.kt diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index 15c3d202..2eb8ce98 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -2,6 +2,8 @@ package com.fasterxml.jackson.module.kotlin import com.fasterxml.jackson.databind.MapperFeature import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.SingletonSupport.CANONICALIZE +import com.fasterxml.jackson.module.kotlin.SingletonSupport.DISABLED import kotlin.reflect.KClass private val metadataFqName = "kotlin.Metadata" @@ -15,7 +17,7 @@ class KotlinModule constructor ( val nullToEmptyCollection: Boolean = false, val nullToEmptyMap: Boolean = false, val nullIsSameAsDefault: Boolean = false, - val enableExperimentalSingletonSupport: Boolean = false + val singletonSupport: SingletonSupport = DISABLED ) : SimpleModule(PackageVersion.VERSION) { @Deprecated(level = DeprecationLevel.HIDDEN, message = "For ABI compatibility") constructor( @@ -49,9 +51,11 @@ class KotlinModule constructor ( context.addValueInstantiators(KotlinInstantiators(cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) - if (enableExperimentalSingletonSupport) { - // [jackson-module-kotlin#225]: keep Kotlin singletons as singletons - context.addBeanDeserializerModifier(KotlinBeanDeserializerModifier) + when(singletonSupport) { + DISABLED -> Unit + CANONICALIZE -> { + context.addBeanDeserializerModifier(KotlinBeanDeserializerModifier) + } } context.insertAnnotationIntrospector(KotlinAnnotationIntrospector(context, cache, nullToEmptyCollection, nullToEmptyMap, nullIsSameAsDefault)) @@ -84,7 +88,7 @@ class KotlinModule constructor ( var nullIsSameAsDefault: Boolean = false private set - var enableExperimentalSingletonSupport = false + var enableExperimentalSingletonSupport = DISABLED private set fun reflectionCacheSize(reflectionCacheSize: Int) = apply { this.reflectionCacheSize = reflectionCacheSize } @@ -96,7 +100,7 @@ class KotlinModule constructor ( fun nullIsSameAsDefault(nullIsSameAsDefault: Boolean) = apply { this.nullIsSameAsDefault = nullIsSameAsDefault } - fun enableExperimentalSingletonSupport(enableExperimentalSingletonSupport: Boolean) = + fun enableExperimentalSingletonSupport(enableExperimentalSingletonSupport: SingletonSupport) = apply { this.enableExperimentalSingletonSupport = enableExperimentalSingletonSupport } fun build() = KotlinModule(this) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/SingletonSupport.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/SingletonSupport.kt new file mode 100644 index 00000000..50e75037 --- /dev/null +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/SingletonSupport.kt @@ -0,0 +1,12 @@ +package com.fasterxml.jackson.module.kotlin + +/** + * Special handling for singletons. + */ +enum class SingletonSupport { + // No special handling of singletons (pre-2.10 behavior) + DISABLED, + // Deserialize then canonicalize (was the default in 2.10) + // [jackson-module-kotlin#225]: keep Kotlin singletons as singletons + CANONICALIZE +} diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt index 6212a9ba..c2d67a34 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt @@ -1,5 +1,7 @@ package com.fasterxml.jackson.module.kotlin +import com.fasterxml.jackson.module.kotlin.SingletonSupport.CANONICALIZE +import com.fasterxml.jackson.module.kotlin.SingletonSupport.DISABLED import org.junit.Assert.* import org.junit.Test import kotlin.reflect.full.memberProperties @@ -20,7 +22,7 @@ class KotlinModuleTest { assertEquals(constructorModule.nullToEmptyCollection, builderModule.nullToEmptyCollection) assertEquals(constructorModule.nullToEmptyMap, builderModule.nullToEmptyMap) assertEquals(constructorModule.nullIsSameAsDefault, builderModule.nullIsSameAsDefault) - assertEquals(constructorModule.enableExperimentalSingletonSupport, builderModule.enableExperimentalSingletonSupport) + assertEquals(constructorModule.singletonSupport, builderModule.singletonSupport) } @Test @@ -31,7 +33,7 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) - assertFalse(module.enableExperimentalSingletonSupport) + assertEquals(DISABLED, module.singletonSupport) } @Test @@ -41,14 +43,12 @@ class KotlinModuleTest { nullToEmptyCollection(true) nullToEmptyMap(true) nullIsSameAsDefault(true) - enableExperimentalSingletonSupport(true) }.build() assertEquals(123, module.reflectionCacheSize) assertTrue(module.nullToEmptyCollection) assertTrue(module.nullToEmptyMap) assertTrue(module.nullIsSameAsDefault) - assertTrue(module.enableExperimentalSingletonSupport) } @Test @@ -61,7 +61,6 @@ class KotlinModuleTest { assertTrue(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) - assertFalse(module.enableExperimentalSingletonSupport) } @Test @@ -74,7 +73,6 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertTrue(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) - assertFalse(module.enableExperimentalSingletonSupport) } @Test @@ -87,19 +85,18 @@ class KotlinModuleTest { assertFalse(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertTrue(module.nullIsSameAsDefault) - assertFalse(module.enableExperimentalSingletonSupport) } @Test - fun builder_EnableExperimentalSingletonSupport() { + fun builder_EnableCanonicalSingletonSupport() { val module = KotlinModule.Builder().apply { - enableExperimentalSingletonSupport(true) + enableExperimentalSingletonSupport(CANONICALIZE) }.build() assertEquals(512, module.reflectionCacheSize) assertFalse(module.nullToEmptyCollection) assertFalse(module.nullToEmptyMap) assertFalse(module.nullIsSameAsDefault) - assertTrue(module.enableExperimentalSingletonSupport) + assertEquals(CANONICALIZE, module.singletonSupport) } } diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt index dda9cc8d..e986083f 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ObjectSingletonTest.kt @@ -2,6 +2,8 @@ package com.fasterxml.jackson.module.kotlin.test import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.SingletonSupport +import com.fasterxml.jackson.module.kotlin.SingletonSupport.CANONICALIZE import com.fasterxml.jackson.module.kotlin.readValue import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat @@ -10,7 +12,7 @@ import org.junit.Test // [module-kotlin#225]: keep Kotlin singletons as singletons class TestObjectSingleton { val mapper: ObjectMapper = ObjectMapper() - .registerModule(KotlinModule(enableExperimentalSingletonSupport = true)) + .registerModule(KotlinModule(singletonSupport = CANONICALIZE)) object Singleton { var content = 1 // mutable state From 974e1a807e544747b9f8a197d6cad6e954e740dd Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Wed, 11 Mar 2020 15:14:31 -0600 Subject: [PATCH 10/11] Shorten singleton support name --- .../com/fasterxml/jackson/module/kotlin/KotlinModule.kt | 8 ++++---- .../fasterxml/jackson/module/kotlin/KotlinModuleTest.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt index 2eb8ce98..1f69f564 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModule.kt @@ -31,7 +31,7 @@ class KotlinModule constructor ( builder.nullToEmptyCollection, builder.nullToEmptyMap, builder.nullIsSameAsDefault, - builder.enableExperimentalSingletonSupport + builder.singletonSupport ) companion object { @@ -88,7 +88,7 @@ class KotlinModule constructor ( var nullIsSameAsDefault: Boolean = false private set - var enableExperimentalSingletonSupport = DISABLED + var singletonSupport = DISABLED private set fun reflectionCacheSize(reflectionCacheSize: Int) = apply { this.reflectionCacheSize = reflectionCacheSize } @@ -100,8 +100,8 @@ class KotlinModule constructor ( fun nullIsSameAsDefault(nullIsSameAsDefault: Boolean) = apply { this.nullIsSameAsDefault = nullIsSameAsDefault } - fun enableExperimentalSingletonSupport(enableExperimentalSingletonSupport: SingletonSupport) = - apply { this.enableExperimentalSingletonSupport = enableExperimentalSingletonSupport } + fun singletonSupport(singletonSupport: SingletonSupport) = + apply { this.singletonSupport = singletonSupport } fun build() = KotlinModule(this) } diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt index c2d67a34..0fb8a4d8 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/KotlinModuleTest.kt @@ -90,7 +90,7 @@ class KotlinModuleTest { @Test fun builder_EnableCanonicalSingletonSupport() { val module = KotlinModule.Builder().apply { - enableExperimentalSingletonSupport(CANONICALIZE) + singletonSupport(CANONICALIZE) }.build() assertEquals(512, module.reflectionCacheSize) From 4601b56563c330a8d6aabceb709584c1790ff7fe Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Wed, 11 Mar 2020 15:32:44 -0600 Subject: [PATCH 11/11] Update version file --- release-notes/VERSION-2.x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 8bd08940..38b99cd9 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -9,7 +9,7 @@ Project: jackson-module-kotlin #284: Use `AnnotationIntrospector.findRenameByField()` to support "is properties" - Add Builder for KotlinModule #281: Hide singleton deserialization support behind a setting on the module, - `enableExperimentalSingletonSupport` + `singletonSupport` and enum `SingletonSupport`. Defaults to pre-2.10 behavior. Kotlin updated to 1.3.61