Skip to content

Added addSerializer and addDeserializer extensions to SimpleModule for registering KClasses #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ Drew Stephens (dinomite@github)

Mateusz Stefek (MateuszStefek@github)
* Reported #321: Make MissingKotlinParameterException a descendant of MismatchedInputException

John Flynn (Neuman968@github)
* Contributed extension methods for SimpleModule to add serializer and deserializer extension functions for KClass #322
(2.12.x)
6 changes: 6 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Project: jackson-module-kotlin
=== Releases ===
------------------------------------------------------------------------

2.12.0 (not yet released)

#322 Added extension methods to SimpleModule addSerializer and addDeserializer to support KClass arguments that
register the serializer/deserializer for both the java type and java class.
-

2.11.1 (not yet released)

-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.MappingIterator
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectReader
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonSerializer
import java.io.File
import java.io.InputStream
import java.io.Reader
import java.net.URL
import kotlin.reflect.KClass

fun jacksonObjectMapper(): ObjectMapper = ObjectMapper().registerKotlinModule()
fun ObjectMapper.registerKotlinModule(): ObjectMapper = this.registerModule(KotlinModule())
Expand All @@ -35,4 +39,14 @@ inline fun <reified T> ObjectReader.readValuesTyped(jp: JsonParser): Iterator<T>
inline fun <reified T> ObjectReader.treeToValue(n: TreeNode): T? = treeToValue(n, T::class.java)

internal fun JsonMappingException.wrapWithPath(refFrom: Any?, refFieldName: String) = JsonMappingException.wrapWithPath(this, refFrom, refFieldName)
internal fun JsonMappingException.wrapWithPath(refFrom: Any?, index: Int) = JsonMappingException.wrapWithPath(this, refFrom, index)
internal fun JsonMappingException.wrapWithPath(refFrom: Any?, index: Int) = JsonMappingException.wrapWithPath(this, refFrom, index)

inline fun <reified T : Any> SimpleModule.addSerializer(kClass: KClass<T>, serializer: JsonSerializer<T>) = this.apply {
addSerializer(kClass.java, serializer)
addSerializer(kClass.javaObjectType, serializer)
}

inline fun <reified T : Any> SimpleModule.addDeserializer(kClass: KClass<T>, deserializer: JsonDeserializer<T>) = this.apply {
addDeserializer(kClass.java, deserializer)
addDeserializer(kClass.javaObjectType, deserializer)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.fasterxml.jackson.module.kotlin.test

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.addDeserializer
import com.fasterxml.jackson.module.kotlin.addSerializer
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test
import java.math.BigDecimal
import java.math.RoundingMode

class KClassSerializerDeserializerTest {

val objectMapper = jacksonObjectMapper()
.registerModule(SimpleModule()
.addSerializer(Double::class, RoundingSerializer())
.addDeserializer(Double::class, RoundingDeserializer()))


@Test
fun `test custom serializer expecting object serialized with rounding serializer applied`() {
val jsonString = objectMapper.writeValueAsString(TestDoubleData(nonNullVal = 1.5567, nullVal = 1.5678))
val testResult = objectMapper.readValue(jsonString, TestDoubleData::class.java)
assertThat(testResult.nonNullVal, equalTo(1.56))
assertThat(testResult.nullVal, equalTo(1.57))
}

@Test
fun `test custom deserializer expecting object deserialized with rounding deserializer applied`() {
val testResult = objectMapper.readValue<TestDoubleData>("""
{
"nonNullVal":1.5567,
"nullVal":1.5678
}
""".trimIndent())
assertThat(testResult.nonNullVal, equalTo(1.56))
assertThat(testResult.nullVal, equalTo(1.57))
}
}

data class TestDoubleData(
val nonNullVal: Double,
val nullVal: Double?
)

class RoundingSerializer : JsonSerializer<Double>() {
override fun serialize(value: Double?, gen: JsonGenerator?, serializers: SerializerProvider?) {
value?.let {
gen?.writeNumber(BigDecimal(it).setScale(2, RoundingMode.HALF_UP))
}
}
}

class RoundingDeserializer : JsonDeserializer<Double>() {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Double? {
return BigDecimal(p?.valueAsString)
.setScale(2, RoundingMode.HALF_UP)
.toDouble()
}
}