develop with

How do I configure jackson object mapper?

Using Jackson and Spring to configure and Object mapper with Kotlin.

When there is a problem trying to deserialize or serialize an object from Kotlin into json, you may need to create your own way to customize the json serialization process. In order to do this in Spring and Kotlin, you’ll need to create a configuration for Jackson that will override the ObjectMapper builder.

Configuration class to customize Jackson:

import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
@Configuration 
class JacksonConfiguration {
    @Bean
    fun customizer(): Jackson2ObjectMapperBuilderCustomizer {
        return Jackson2ObjectMapperBuilderCustomizer { builder -> builder.modules(myModule()) }
    }

    @Bean
    fun myModule() : Module {
        return MyModule()
    }
}

In the above class, we specify a MyModule that will override the specifics by using the built in Jackson Module approach. This will add to the behavior of Jackson without completely overriding all the defaults. The MyModule will add a custom deserializer that will help with the problem areas of your deserialization issues.

My Module example class:

import com.fasterxml.jackson.databind.Module
import com.fasterxml.jackson.databind.module.SimpleModule

class MyModule : SimpleModule() {

    override fun setupModule(context: Module.SetupContext) {
        super.setupModule(context)
        context.addDeserializationProblemHandler(JsonProblemHandler())
    }
}

The handler is the key part that is used to address the changes needed for the json deserializing. It extends the DeserializationProblemHandler to handle the issues that aren’t handled by the default deserialization in Jackson. In this case, we look for a specific object that is part of an object chain. The object chain would look something like this:

class MyAbstractEntity {
}

class MyEntity : MyAbstractEntity {
}

When we see the concrete class we make sure the base type is returned instead of following the default path. This type of approach can also be used to override property deserialization, etc… with different handlers and listeners added to the module context.

import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JavaType
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver

class JsonProblemHandler : DeserializationProblemHandler() {

    override fun handleMissingTypeId(
        ctxt: DeserializationContext?,
        baseType: JavaType?,
        idResolver: TypeIdResolver?,
        failureMsg: String?
    ): JavaType {
        // return base class if specific type is found
        if(baseType != null && baseType.isTypeOrSuperTypeOf(MyEntity::class.java)) {
            return baseType
        }

        return super.handleMissingTypeId(ctxt, baseType, idResolver, failureMsg)
    }
}

Some more ideas can be seen over on Stack Overflow’s q & a related to the above.

Another option for the above problem could be Overriding the TypeIdResolver.

comments powered by Disqus

Want to see a topic covered? create a suggestion

Get more developer references and books in the developwith store.