kotlinannotationscompile-time-constantgraphql-spqr

How to create compile-time constant in Kotlin from enum?


I have an annotation that requires defaultValue to be compile-time constant. I take defaultValue from enum below:

enum class RaceType {
    MARATHON,
    SPRINT;

    companion object {
        fun apply(type: RaceType): RaceDto {
            return when (type) {
                MARATHON -> MarathonDto()
                SPRINT -> SprintDto()
            }
        }
    }
}

My dtos are the following:

interface RaceDto {
}

data class MarathonDto: RaceDto

data class SprintDto: RaceDto

when I use annotation @QraphQLArgument(defaultValue = RaceType.SPRINT.name) Kotlin requires RaceType.SPRINT.name to be compile-time constant.

Annotation implementation itself:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface GraphQLArgument {
    String NONE = "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
    String NULL = "\n\t\t\n\t\t\n\ue000\ue001\ue002\ue003\n\t\t\t\t\n";

    String name();

    String description() default "";

    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";

    Class<? extends DefaultValueProvider> defaultValueProvider() default JsonDefaultValueProvider.class;
}

I looked through similar questions but don't see a way how it can be resolved. I also found article related to the topic but nothing worked so far.

Side note: I cannot change annotation since it is from the library and I cannot change the library as well.

To summarize, is there a way to make from enum compile-time constant in Kotlin to use in an annotation?


Solution

  • is there a way to make from enum compile-time constant in Kotlin to use in an annotation?

    No, because formally enums aren't compile-time constants in Java.

    However please consider the sealed classes:

    sealed class RaceType {
        object MARATHON: RaceType() {
            const val name = "MARATHON" // copy-paste is required here until https://youtrack.jetbrains.com/issue/KT-16304
        }
        object SPRINT: RaceType()
    
        companion object {
            fun apply(type: RaceType): RaceDto {
                return when (type) { // the check is in compile time, because of sealed class
                    MARATHON -> MarathonDto()
                    SPRINT -> SprintDto()
                }
            }
        }
    }
    

    A little part of copy-paste is still required. Please vote on kotlin compiler bug or follow this thread.

    However, as I understand, this doesn't solve your issue with @QraphQLArgument(defaultValue = RaceType.SPRINT.name) unfortunately, because the name of class is not the same with value. In the other words, with sealed classes you need to write code to convert input strings to them.