Search code examples
kotlinenumsjacksonannotations

How to get Jackson JsonProperty of enum values in Kotlin?


I'm building a schema generator and I'm trying to get the JsonProperty of enum values, for example, for this class:

enum class Size {
    @JsonProperty("really-tall") TALL,
    @JsonProperty("really-grande") GRANDE;
}

I'd like to get the list "really-tall", "really-grande".

How do I access the annotation of an enum? Thanks!

UPDATE:

Solution based on this reply for a generic KType:

return (jvmErasure.java as Class<Enum<*>>)
  .enumConstants
  .map {
    it.javaClass.getField(it.name).getAnnotation(JsonProperty::class.java)?.value // Get the JsonProperty string first if exists
      ?: it.name
  }

Solution

  • Update: Additional question from OP

    How do I make the first approach work for a generic KType

    inline fun <reified T : Enum<T>> getJsonPropertyAnnotations() = enumValues<T>().map {
        it.declaringClass
            .getField(it.name)
            .getAnnotation(JsonProperty::class.java)
            .value
    }
    
    class SomeTest : StringSpec({
        "getJsonPropertyAnnotations" {
            getJsonPropertyAnnotations<Size>() 
                shouldBe listOf("really-tall", "really-grande")
        }
    })
    

    Please note that with Kotlin 1.7, IntelliJ may show a deprecation warning with wrong replacement for declaringClass in getJsonPropertyAnnotations. I guess this will be sorted out in later versions. Link to related source


    The following code should do what you want.

    class SomeTest : StringSpec({
        "getting annotation values" {
            val result = enumValues<Size>().map {
                it.declaringClass.getField(it.name).getAnnotation(JsonProperty::class.java).value
            }
            result shouldBe listOf("really-tall", "really-grande")
        }
    })
    

    An alternative (less code): Add a String property to your enum class (I called it someFieldName in the below code), annotate with @get:JsonValue, and construct each enum entry with the string value you want. @get:JsonValue will use someFieldName instead of the enum value during serialization.

    enum class Size(@get:JsonValue val someFieldName: String) {
        TALL("really-tall"),
        GRANDE("really-grande");
    }
    

    Same test again

    class SomeTest : StringSpec({
        "getting prop values" {
            val result = enumValues<Size>().map {
                it.someFieldName
            }
            result shouldBe listOf("really-tall", "really-grande")
        }
    })
    

    We're using the latter approach in an ongoing project.