Home > Back-end >  Spring boot serialize kotlin enum by custom property
Spring boot serialize kotlin enum by custom property

Time:06-22

I have an Enum and I would like to serialize it using custom property. It works in my tests but not when I make request.

Enum should be mapped using JsonValue

enum class PlantProtectionSortColumn(
    @get:JsonValue val propertyName: String,
) {

    NAME("name"),
    REGISTRATION_NUMBER("registrationNumber");

}

In test the lowercase case works as expected.


class PlantProtectionSortColumnTest : ServiceSpec() {

    @Autowired
    lateinit var mapper: ObjectMapper

    data class PlantProtectionSortColumnWrapper(
        val sort: PlantProtectionSortColumn,
    )

    init {
        // this works
        test("Deserialize PlantProtectionSortColumn enum with custom name ") {
            val json = """
                {
                    "sort": "registrationNumber"
                }
            """
            val result = mapper.readValue(json, PlantProtectionSortColumnWrapper::class.java)
            result.sort shouldBe PlantProtectionSortColumn.REGISTRATION_NUMBER
        }

        // this one fails
        test("Deserialize PlantProtectionSortColumn enum with enum name ") {
            val json = """
                {
                    "sort": "REGISTRATION_NUMBER"
                }
            """
            val result = mapper.readValue(json, PlantProtectionSortColumnWrapper::class.java)
            result.sort shouldBe PlantProtectionSortColumn.REGISTRATION_NUMBER
        }
    }
}


But in controller, when i send request with lowercase I get 400. But when the request matches the enum name It works, but response is returned with lowercase. So Spring is not using the objectMapper only for request, in response it is used.

private const val RESOURCE_PATH = "$API_PATH/plant-protection"


@RestController
@RequestMapping(RESOURCE_PATH, produces = [MediaType.APPLICATION_JSON_VALUE])
class PlantProtectionController() {

    @GetMapping("/test")
    fun get(
        @RequestParam sortColumn: PlantProtectionSortColumn,
    ) = sortColumn

}

CodePudding user response:

In your endpoint you are not parsing json body but query parameters, which are not in json format.

CodePudding user response:

I believe kqr's answer is correct and you need to configure converter, not JSON deserializer.

It could look like:

class StringToPlantProtectionSortColumnConverter : Converter<String, PlantProtectionSortColumn> {

override fun convert(source: String): PlantProtectionSortColumn {
    return PlantProtectionSortColumn.values().firstOrNull { it.propertyName == source }
        ?: throw NotFoundException(PlantProtectionSortColumn::class, source)
}}

And do not forget to register it :

@Configuration
class WebConfig : WebMvcConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
    registry.addConverter(StringToPlantProtectionSortColumnConverter())
}}
  • Related