Jörg Vollmer
Jörg Vollmer

Reputation: 198

How to access Enum property and functions in Kotlin

The following enum definition is valid. Is it possible to access the "inner property" auditData or function auditor?

enum class GWGStatus {
    UNCHECKED,
    CHECKED {
        lateinit var auditDate: Date
        fun auditor() : String = "Peter"
    }
}

GWGStatus.CHECKED.??? (does not work)

Upvotes: 5

Views: 6376

Answers (3)

Roland
Roland

Reputation: 23242

As soon as I saw this I just needed to look up the bytecode as I couldn't imagine what this should be translated to. While I believe "it" is a bug, I will show you what I found out so far.

For CHECKED there is actually created its own subclass, i.e. public final class GWGStatus$CHECKED extends GWGStatus even though GWGStatus is an enum itself. Probably again something that is allowed in the JVM bytecode, but isn't allowed in the Java language specification.

Now comes the not-so-congruent part. While the following works in Java:

GWGStatus.CHECKED status = (GWGStatus.CHECKED) GWGStatus.CHECKED;
status.auditDate = new Date();
System.out.println(status.auditor());

and prints Peter as expected, the cast isn't possible in Kotlin (yet?):

GWGStatus.CHECKED as GWGStatus.CHECKED // fails: Use of enum entry names as types is not allowed, use enum type instead

Now using java reflection utilities in Kotlin (e.g. status::class.java.declaredFields or .java.declaredMethods) both auditor() and getAuditDate() (etc.) are visible and accessible (as was already proven by the Java code itself). Analysing further and just using Kotlin reflection instead:

GWGStatus.UNCHECKED::class // returns class GWGStatus
GWGStatus.CHECKED::class // return class GWGStatus$CHECKED ... that's good so far
GWGStatus.CHECKED::class.declaredMembers // empty list ... didn't expect this one
// empty too: GWGStatus.CHECKED::class.declaredMemberProperties
// and GWGStatus.CHECKED::class.declaredFunctions
GWGStatus.CHECKED::class.superTypes // shows GWGStatus as expected
GWGStatus.CHECKED::class.members // shows clone(), finalize(), name, equals, hashcode, tostring, getdeclaringclass, ordinal... nothing we are interested in and rather the ~general enum members
GWGStatus::class.nestedClasses // empty too

Ok... we can't see them using Kotlin reflection (or maybe I did not use the right approach? ;-)). So: something smells like a bug here, but I am not sure yet what the bug is:

  1. is it that there should not have been created a subclass in the first place?
  2. is it that the subclass should be accessible and visible in Kotlin itself?
  3. is it that the Kotlin compiler should have complained about this as this is not a finished feature yet?
  4. is in fact the error message wrong and it should just have allowed the cast?
  5. something else?

Upvotes: 4

Maksym V.
Maksym V.

Reputation: 2937

You can also just use the constructor:

enum class GWSGStatus(var date: Date, private var auditor: String) {
    UNCHECKED(Date(), ""),
    CHECKED(Date(), "Peter");

    fun auditor() = auditor
}

It still depends on the usage of this enum. Pay attention to previous post

Upvotes: 0

Robby Cornelissen
Robby Cornelissen

Reputation: 97130

You would have to declare the variables and functions in the enum type itself and then override them in the enum instances.

Unfortunately, since not all your enum instances implement the function, you can't make it abstract and have to provide a default implementation:

import java.util.*

enum class GWGStatus {
    UNCHECKED,
    CHECKED {
        override lateinit var auditDate: Date
        override fun auditor(): String = "Peter"
    };

    open lateinit var auditDate: Date
    open fun auditor(): String = ""
}

fun main(vararg args: String) {
    GWGStatus.CHECKED.auditDate = Date()

    println(GWGStatus.CHECKED.auditDate)
    println(GWGStatus.CHECKED.auditor())
}

Note however, that this enum usage feels really strange. You're storing state data in something that is intended to be a constant object. There will only ever be one GWGStatus.CHECKED object in memory, so it doesn't seem like the right place to store state information.

Upvotes: 3

Related Questions