How to deserialize WWW form field to enum in Spring?

Viewed 976

I'm facing issue when trying deserialize input coming from WWW form to enum class in Spring application, in Kotlin.

My DTO and enum classes:

enum class Status(@get:JsonValue val value: Int) {
    NORMAL(0),
    ERROR(1);

    companion object {
        @JvmStatic
        @JsonCreator
        fun of(number: Int?): Status? {
            return values().find { it.value == number }
        }
    }
}

data class RequestData(val status: Status?)

Controller's POST request receiver method:

@PostMapping("/post")
fun register(@Valid data: RequestData, error: Errors) {}

When I make POST request with status = 0 using Postman, request's failing with following exception.

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method com.example.Controller.post, parameter data

When I make request with status = NORMAL then no exception, but that what I don't want. I'm using application/x-www-form-urlencoded content type in POST request. Please let me know where I'm doing wrong.

3 Answers

You just use the name.

ex) status = NORMAL

And does value matter? You can use ordinal

enum class Status{
    NORMAL,
    ERROR,
}

println(NORMAL.ordinal)
//result:0

This is a joke, but if you need

enum class Status(val value:String){
    `0`("NORMAL"),`1`("ERROR")
}

println(data.status.value)

You may use Converter class for that. Note that request parameters my look like a numbers to you, but they are in fact strings. That's why converter below accepts String? and returns Status?. That means, it would be convenient for you if your enum accept it as well. Example: NORMAL("0"), ERROR("1").

class ConvStringToStatus : Converter<String?, Status?> {
    override fun convert(source: String?) = Status.of(source)
}

To make it work, converter must be registered as below.

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

For anyone still looking and finding this. The example code works and does not throw non-null field is null exception if you add jackson-module-kotlin dependency. It should match your com.fasterxml.jackson.core version

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-kotlin</artifactId>
    <version>2.9.8</version>
</dependency>
Related