The issue, really, is in Jackson's API here. Here's how the readValue method is declared:

public <T> T readValue(String content, TypeReference valueTypeRef)

They are using the raw type of TypeReference for some reason, even though they could easily take a TypeReference<T> as their parameter. If they did, you code would work as is, as Kotlin could then infer the T generic type parameter of the function, and therefore know its return type.

You can work around this issue a couple different ways, however, by being explicit with your types.

  • Either by providing the generic type parameter for the function, and having the type of the msg variable inferred:

      val typeRef: TypeReference<Map<K, V>> = object : TypeReference<Map<K, V>>() {} 
      val msg = objectMapper.readValue<HashMap<String, String>>(message.payload, typeRef)
    
  • Or alternatively, by explicitly typing your variable, and having the function's type parameter inferred:

      val msg: HashMap<String, String> = objectMapper.readValue(message.payload, typeRef)
    
Answer from zsmb13 on Stack Overflow
🌐
Stack Abuse
stackabuse.com › reading-and-writing-json-in-kotlin-with-jackson
Reading and Writing JSON in Kotlin with Jackson
February 27, 2023 - import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper // Registering the Kotlin module with the ObjectMapper instance val mapper = jacksonObjectMapper() // JSON String val jsonString = """{ "id":101, "username":"admin", "password":"Admin123", "fullName":"Best Admin" }""" With that done, we can pass JSON contents into our ObjectMapper methods, such as readValue(), as usual for Jackson: // Read data from a JSON string val userFromJson = mapper.readValue<User>(jsonString) // Or val userFromJsonWithType: User = mapper.readValue(jsonString) If we print the value of userFromJson we'll see something like this: User(id=101, username=admin, password=Admin123, fullName=Best Admin) The readValue() function can be used with or without the Class parameter, as you saw a little earlier with the two variables (userFromJson and userFromJsonWithType).
🌐
Baeldung
baeldung.com › home › libraries › jackson support for kotlin
Jackson Support for Kotlin | Baeldung on Kotlin
August 26, 2026 - @Test fun whenDeserializeMap_thenSuccess() { val json = """{"1":"one","2":"two"}""" val aMap: Map<Int,String> = mapper.readValue(json) assertEquals(aMap[1], "one") assertEquals(aMap[2], "two") } Now, we’ll see how to serialize collections in Kotlin. Here we have a List of movies that we want to serialize to a JSON String:
🌐
Medium
bijukunjummen.medium.com › jackson-kotlin-extension-and-reified-types-2143015df62a
Jackson Kotlin extension and reified types | by Biju Kunjummen | Medium
May 30, 2023 - import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue val objectMapper = jacksonObjectMapper() val result: Map<String, List<String>> = objectMapper.readValue(json)
🌐
BezKoder
bezkoder.com › home › kotlin – convert json to object and vice versa using jackson
Kotlin – Convert JSON to Object and vice versa using Jackson - BezKoder
December 13, 2020 - package com.bezkoder.kotlin.json data class Person(val name: String, val age: Int, val messages: List · ) { } The example shows you way to use ObjectMapper.readValue() function to: convert JSON String to Kotlin object · convert JSON URL to Kotlin object · convert JSON file to Kotlin object ·
🌐
Educative
educative.io › answers › parsing-api-data-in-kotlin-using-jackson
Parsing API data in Kotlin using Jackson
val jsonBody = objectMapper.readValue<DTO>(body) return jsonBody · } } That’s it - we’re now able to call an external API and deserialize​ the response into a workable format. Next, we’ll learn how to save our results in a database. Jackson for Kotlin ·
🌐
Kotlin Discussions
discuss.kotlinlang.org › language design
How to specify generic output type to be subclass of generic type - Language Design - Kotlin Discussions
April 16, 2022 - In Kotlin scratch file: import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.ko...
Top answer
1 of 4
67

With Jackson Kotlin Module current versions, if you import the full module package or the specific extension function you'll have all extension methods available. Such as:

import com.fasterxml.jackson.module.kotlin.*  
val JSON = jacksonObjectMapper()  // keep around and re-use
val myList: List<String> = JSON.readValue("""["a","b","c"]""")

Therefore the Jackson Module for Kotlin will infer the the correct type and you do not need a TypeReference instance.

so your case (slightly renamed and fixed the data class, and JSON):

import com.fasterxml.jackson.module.kotlin.readValue

data class MyData(val a: String, val b: Int)
val JSON = jacksonObjectMapper()  

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b": 2}]"""
val myList: List<MyData> = JSON.readValue(jsonStr)

You can also use the form:

val myList = JSON.readValue<List<MyData>>(jsonStr)

Without the import you will have an error because the extension function is not found.

2 of 4
25

TL;DR

With Jackson 2.6.3-2 do as @jason-minard advises and simply use:

import com.fasterxml.jackson.module.kotlin.readValue

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

Details

There's nothing special about Kotlin wrt to deserializing collections, although you'll need the kotlin jackson module to deserialize data classes without annotations.

Namely, it will require full reified type information in your case in order to keep track of the generic parameter of the list (D) ; otherwise (e.g. if you use readValue(jsonStr, List::class.java)) Jackson will only see it as an erased type (i.e. List) (as Kotlin makes explicit) and deserialize it to a List<Map<String, String>>, not knowing it has to construct Ds. This is worked around by using an anonymous subclass of TypeReference in Java so that Jackson can access the full reified type to deserialize to at run time.

Translating Jackson Java code literally to Kotlin, the following thus achieves what you want (and as commented by @eski, notice that the JSON in your example is invalid):

val jacksonMapper = ObjectMapper().registerModule(KotlinModule())

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":2}]"""
val listOfD: List<D> = jacksonMapper.readValue(jsonStr, object : TypeReference<List<D>>(){})

assertEquals(listOf(D("value1", 1), D("value2", 2)), listOfD)

This is a bit verbose and ugly though, so you could hide it in a Kotlin (extension) function (especially if you plan on using it several times):

inline fun <reified T> ObjectMapper.readValue(json: String): T = readValue(json, object : TypeReference<T>(){})

which would allow you to then just call:

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

And this is just what's included in the 2.6.3-2 jackson Kotlin module.

Find elsewhere
🌐
GitHub
github.com › FasterXML › jackson-module-kotlin › issues › 480
The ObjectMapper.readValue extension methods need the type param to be bound to Any · Issue #480 · FasterXML/jackson-module-kotlin
July 22, 2021 - class Foo(val value: Int) // any class val mapper = ObjectMapper().registerKotlinModule() val deserialized = mapper.readValue<Foo>("null") // succeeds println(deserialized) // null · Expected behavior Deserialization should fail when the declared type parameter is not explicitly nullable · Versions Kotlin: 1.4 Jackson-module-kotlin: 2.13 Jackson-databind: 2.13 ·
Author: FasterXML
🌐
DZone
dzone.com › coding › languages › kotlin: reified type parameters
Kotlin: Reified Type Parameters
January 26, 2018 - inline fun <reified T> ObjectMapper.readValue(s: String): T = this.readValue(s, object : TypeReference<T>() {}) The inline function is the heart of the support to be able to reify generic type parameters here — after compilation, the function would be expanded out into any place this function is called, and thus, the second version is exactly same as the first version of the test — but reads far better than before. Note that Jackson already implements these Kotlin extension functions in the excellent jackson-module-kotlin library.
🌐
CodeSignal
codesignal.com › learn › courses › handling-json-files-with-kotlin-2 › lessons › parsing-json-arrays-in-kotlin-with-jackson
Parsing JSON Arrays in Kotlin with Jackson
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import java.nio.file.Files import java.nio.file.Paths // Path to the JSON file val filePath = Paths.get("data.json") // Read the content of the JSON file into a string val json = Files.readString(filePath) // Initialize ObjectMapper instance val objectMapper = jacksonObjectMapper() // Decode the JSON string into a Company object val company: Company = objectMapper.readValue(json) This code allows us to convert JSON data into a Kotlin Company object, which can then be manipulated using Kotlin’s robust data-handling features. ... Once we have our JSON data mapped into Kotlin objects, the next step involves iterating through arrays. JSON arrays, represented as List<E> in Kotlin, require traversal to access individual elements for data processing.
🌐
Mario Fernandez
hceris.com › painless json with kotlin and jackson
Painless JSON with Kotlin and jackson | Mario Fernandez
June 16, 2019 - data class User(val id: String, val age: Int) fun User.toJson(): String = ObjectMapper().writeValueAsString(this) fun String.toUser(): User = ObjectMapper().readValue(this)
🌐
GitHub
github.com › FasterXML › jackson-module-kotlin › issues › 145
ObjectMapper (with KotlinModule) not detecting single String constructor but without KotlinModule it does · Issue #145 · FasterXML/jackson-module-kotlin
April 8, 2018 - class Person(@JsonProperty("preName") val preName:String, @JsonProperty("lastName") val lastName:String) { constructor(preNameAndLastName:String): this(preNameAndLastName.substringBefore(","),preNameAndLastName.substringAfter(",")) } @Test fun workingTestWithoutKotlinModule() { val objectMapper = ObjectMapper() val person1 = objectMapper.readValue("""{"preName":"TestPreName","lastName":"TestLastname"}""",Person::class.java) val person2 = objectMapper.readValue(""""TestPreName,TestLastname"""",Person::class.java) } @Test fun notWorkingTestWithKotlinModule() { val objectMapper = ObjectMapper().registerModule(KotlinModule()) val person1 = objectMapper.readValue("""{"preName":"TestPreName","lastName":"TestLastname"}""",Person::class.java) val person2 = objectMapper.readValue(""""TestPreName,TestLastname"""",Person::class.java) } No one assigned ·
Author: FasterXML
🌐
Medium
medium.com › @bartlomiej.bobak › deserializing-a-kotlin-object-using-jackson-may-not-work-as-you-expect-1e01003cc0f0
Deserializing a Kotlin object using Jackson may not work as you expect | by Bartłomiej Bobak | Medium
February 12, 2023 - @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "type" ) sealed class Scope { object All : Scope() data class Specific(val value: String): Scope() } fun main() { val objectMapper = ObjectMapper().registerKotlinModule() val json = objectMapper.writeValueAsString(Scope.All) val scope = objectMapper.readValue<Scope>(json) when (scope) { Scope.All -> println("All") is Scope.Specific -> println(scope.value) } }
🌐
GitHub
github.com › FasterXML › jackson-module-kotlin › issues › 573
How to properly configure an ObjectMapper to handle kotlin-specific integer types? · Issue #573 · FasterXML/jackson-module-kotlin
June 22, 2022 - I would like to ask how to properly configure an ObjectMapper to make it capable of deserializing data classes with kotlin-specific integer fields. Out of the box it works e.g. with raw UInts: val actual: UInt = objectMapper.readValue("4294967295") val expected: UInt = 4294967295u assertThat(actual).isEqualTo(expected) However, a simple data class like this ·
Author: FasterXML
🌐
Continuous Growth
kapentaz.github.io › home › kotlin › json
Kotlin and Jackson (ObjectMapper) - Continuous Growth
March 14, 2020 - data class SampleRequest( val ticketNo: Int, val name: String, val discount: BigDecimal, val couponNos: List<Int>, val extraInfo: Map<String, Any> ) 위 내용으로 Jackson의 ObjectMapper를 이용해서 실행해보면… · objectMapper.readValue<SampleRequest>(json, SampleRequest::class.java)
🌐
Stefanhendriks
stefanhendriks.com › 2021 › 01 › 29 › deserialise-json-to-typed-map-with-jackson-in-kotlin
Deserialise Json to typed Map with Jackson in Kotlin – Stefan Hendriks' blog
January 29, 2021 - val map = if (StringUtils.isEmpty(json)) { HashMap<MyEnum, Int>() } else { val typeRef: TypeReference<Map<MyEnum, Int>> = object : TypeReference<Map<MyEnum, Int>>() {} objectMapper.readValue(json, typeRef) }
🌐
GitHub
github.com › FasterXML › jackson-module-kotlin › issues › 412
Deserialization of Map<Enum, Int> fails with generic implementation, works with concrete? (Kotlin) · Issue #412 · FasterXML/jackson-module-kotlin
January 29, 2021 - @Test fun deserializeAsMapWithEnumKey() { val mapper = ObjectMapper() mapper.registerModule(KotlinModule()) // create JSON first: var theMap: Map<LuggageType, Int> = mapOf(LuggageType.LARGE to 3, LuggageType.SMALL to 2) var json = mapper.writeValueAsString(theMap) System.out.println(json) // {"LARGE":3,"SMALL":2} // Now read the JSON: val typeRef: TypeReference<HashMap<LuggageType, Int>> = object : TypeReference<HashMap<LuggageType, Int>>() {} val mapRead = mapper.readValue(json, typeRef) System.out.println(mapRead) // {LARGE=3, SMALL=2} Assert.assertEquals(2, mapRead.keys.size) // Check enums are read Assertions.assertThat(mapRead.keys).contains(LuggageType.SMALL, LuggageType.LARGE) } However, we use a util class (called SwissKnife) with some generics stuff in it.
Author: FasterXML
🌐
GitHub
github.com › FasterXML › jackson-module-kotlin › issues › 1095
Jackson3 Error when Deserializing List<Map<String,Any?>> as property of object · Issue #1095 · FasterXML/jackson-module-kotlin
February 7, 2026 - data class Wrapper1(val value: Map<String,Any?>) data class Wrapper2(val values: List<Map<String,Any?>>) val mapper = jacksonMapperBuilder() .enable(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN) .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) .enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION) .build() // works @Test fun `single map without wrapper`() { val json = """ { "name": "something", "value": null } """.trimIndent() val map = mapper.readValue<Map<String,Any>>(json) assertThat(map).hasSize(2) } // works @Test fun `single map as property`() { val json = """ { "value": { "name": "so
Author: FasterXML