Adding a property to an existing enum in Kotlin - enums

Given the following enum defined in an external api.
public enum Status {
COMPLETE,
RUNNING,
WAITING
}
I would like a way to add a int flag to each enum value. I know that I can extend the enum:
fun Status.flag(): Int {
when(this) {
RUNNING -> return 1;
WAITING -> return 2;
else -> return 0;
}
}
However I would like to define those int flag values as constants. Maybe a companion object, but I don't think I can extend an existing enum and add a companion object.
Any ideas?

Unless you are using a field that already exists in the original enum (like ordinal), you won't be able to do what you're asking without wrapping the external enum in your own enum.
Sure you could use ordinal, but a newer version of the external API may change the order of the items in the enum, so I wouldn't recommend it. But, if you REALLY want to, you could do something like this (again, this is NOT recommended):
val Status.flag: Int
get() = this.ordinal
But I'd definitely recommend wrapping it. That way you guarantee that the flag integers you define won't change.
enum class MyStatus(val status: Status, val flag: Int) {
COMPLETE(Status.COMPLETE, 0),
RUNNING(Status.RUNNING, 1),
WAITING(Status.WAITING, 2);
companion object {
private val STATUS_TO_MYSTATUS = values().associateBy { it.status }
fun fromStatus(status: Status): MyStatus {
return STATUS_TO_MYSTATUS[status] ?: throw Exception("No MyStatus found for status ${status.name}")
}
}
}
You can then convert Status to MyStatus by using MyStatus.fromStatus(...). Or you can add an extension function to Status to easily convert to MyStatus.
fun Status.toMyStatus() = MyStatus.fromStatus(this)

You can add extension properties/methods to the companion object of enum/class/etc. if one exists:
val Status.Companion.COMPLETE_INT = 0
val Status.Companion.RUNNING_INT = 1
but indeed you can't currently "create" the companion object if it doesn't. So just put the constants into your own non-companion object:
object StatusFlags {
const val COMPLETE_INT = 0
const val RUNNING_INT = 1
const val WAITING_INT = 2
}
fun Status.flag(): Int {
when(this) {
RUNNING -> return StatusFlags.RUNNING_INT
...
}
}

Related

Springboot Kickstart GraphQL - Metrics for number of requests per resolver

I am currently trying in SpringBoot GraphQL kickstart to track the number of times each resolver method is called. To be more specific, I want to exactly how many times the methods of my GraphQLResolver<T> are called. This would have two utilities:
Track if the deprecated resolvers are still used
Know which fields are the most used, in order to optimize the database queries for those
To do so, I implemented a really weird and not-so-clean way using schema directive wiring.
#Component
class ResolverUsageCountInstrumentation(
private val meterRegistry: MeterRegistry
) : SchemaDirectiveWiring {
private val callsRecordingMap = ConcurrentHashMap<String, Int>()
override fun onField(environment: SchemaDirectiveWiringEnvironment<GraphQLFieldDefinition>): GraphQLFieldDefinition {
val fieldContainer = environment.fieldsContainer
val fieldDefinition = environment.fieldDefinition
val currentDF = environment.codeRegistry.getDataFetcher(fieldContainer, fieldDefinition)
if (currentDF.javaClass.name != "graphql.kickstart.tools.resolver.MethodFieldResolverDataFetcher") {
return fieldDefinition
}
val signature = getMethodSignature(unwrappedDF)
callsRecordingMap[signature] = 0
val newDF = DataFetcherFactories.wrapDataFetcher(currentDF) { dfe: DataFetchingEnvironment, value: Any? ->
callsRecordingMap.computeIfPresent(signature) { _, current: Int -> current + 1 }
value
}
environment.codeRegistry.dataFetcher(fieldContainer, fieldDefinition, newDF)
return fieldDefinition
}
private fun getMethodSignature(currentDF: DataFetcher<*>): String {
val method = getFieldVal(currentDF, "resolverMethod", true) as Method // nonapi.io.github.classgraph.utils.ReflectionUtils
return "${method.declaringClass.name}#${method.name}"
}
}
This technique does the work, but has the big disadvantage of not working if the data fetcher is wrapped. Along with that, it's not really clean at all. I'm wondering, would there be a better way to do this?
Thank you!

kotlin safe conversion from string to enum

I need to convert strings to Enum values, but want a function which returns null if the string is not an enum.
enum class Colors{
Red, Green, Blue
}
I can used Colors.valueOf(testString) provided testString is value, but there will be an exception if it is not valid, and I want a null in that case.
Because I want to this often, an extension function would be ideal. But the extension needs to operate on the class Colors, and not an object of type Colors.
Anyone know how to write such an extension? Ideally one that is generic for any enum class.
It is simple to write a top level function, but I am seeking one that acts as the standard 'method' does
// instead of
val willGetAnException = Colors.valueOf("Yellow") // standard existing fun
val willGetNull = Colors.valueOrNullOf("Orange") // new fun i seek
And ideally one that is generic and works for any enum
You don't want an extension since they must be invoked on an existing object. You want a top-level function. There is a built in one You can use:
/**
* Returns an enum entry with specified name.
*/
#SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T
You can call it by inferring the type, or explicitly:
val a : MyEnumClass = enumValueOf("A")
val b = enumValueOf<MyEnumClass>("B")
However this method is not nullable: it throws java.lang.IllegalArgumentException on unknown values.
But it's easy to mimick it's behavior and have it work for nullable enums with a top level function:
inline fun <reified T : Enum<*>> enumValueOrNull(name: String): T? =
T::class.java.enumConstants.firstOrNull { it.name == name }
Colors.values().find { it.name == "Yellow" }
You can use something like this :
inline fun <reified T : Enum<T>> String.asEnumOrDefault(defaultValue: T? = null): T? =
enumValues<T>().firstOrNull { it.name.equals(this, ignoreCase = true) } ?: defaultValue
Then: "Yellow".asEnumOrDefault(Colors.Green)
Or, if you it can't be infered: "Yellow".asEnumOrDefault<Colors>()
enum class Colors {
BLACK, WHITE, UNKNOWN;
companion object {
// Verbose for illustrative purposes
fun fromOrdinal(ordinal: Int): Colors = values()[ordinal]
fun fromOrdinalOrNull(ordinal: Int): Colors? = values().getOrNull(ordinal)
fun fromOrdinalOrDefault(ordinal: Int): Colors = values().getOrElse(ordinal) { UNKNOWN }
fun fromName(name: String): Colors = valueOf(name.uppercase())
fun fromNameOrNull(name: String): Colors? = values().find { it.name == name.uppercase() }
fun fromNameOrDefault(name: String): Colors = values().find { it.name == name.uppercase() } ?: UNKNOWN
}
}
Given the fact it's not easy to access the Enum value safely in Kotlin, I published a library enum-or-null-kt to provide a collection of shorthand functions which makes you can write code like below:
class Example {
enum class Direction(val az: Int) {
NORTH(0),
EAST(90),
SOUTH(180),
WEST(240)
}
fun printAz01(name: String = "EAST") {
val direction = enumValueOrNull<Direction>(name) ?: Direction.EAST
println("az01=${direction.az}")
}
fun printAz02(name: String = "EAST") {
val direction = name.toEnumOrNull<Direction>() ?: Direction.EAST
println("az02=${direction.az}")
}
fun printName01(az: Int = 0) {
val direction = enumValueOrNull<Direction> {
it.az == az
} ?: Direction.NORTH
println("name03=${direction.name}")
}
fun printName02(ordinal: Int = 0) {
val direction = enumValueOrNull<Direction> {
it.ordinal == ordinal
} ?: Direction.NORTH
println("name03=${direction.name}")
}
}
With it, not only can you access the Enum value with names, but also you can pass an arbitrary higher-order function as a predicate clause. That is convenient when you need to deal with a custom conversion such as JPA attribute converters.
The Kotlin API does not work by simply using <reified T: Enum<T>>. It throws an exception of the type InvocationTargetException. So I pass directly to type: Class<T> by parameter.
private fun <T> enumValueOf(type: Class<T>, enum: String) : T {
return type.enumConstants.first { it.toString() == enum }
}
Using
if (type.isEnum) enumValueOf(#Field.type, value as String)

how to convert to NotNull by using enum in Kotlin

How can I convert the following code to accepted NotNull inside enum class by using Kotlin?
Note: i'm using this enum between two activity and one activity has 2 adapters.
Here is enum class
enum class Adapterx {
ADAPTER_1,
ADAPTER_2;
companion object {
fun fromOrdinal(ordinal: Int): Adapterx? {
return Adapterx.values().firstOrNull { it.ordinal == ordinal }
}
}
}
Since you cannot restrict the ordinal: Int parameter as you've define it, you have two choices if you receive an ordinal which is not part of the enum, or is out of bounds:
Return a default value
Throw an exception
IMHO both cases are plausible if you document properly the method.
Here's a case where you return just a default value if you ask for an ordinal that does not exist:
class KotlinEnumTest {
enum class Adapterx {
ADAPTER_1,
ADAPTER_2;
companion object {
val defaultValue = ADAPTER_1
fun fromOrdinal(ordinal: Int): Adapterx =
Adapterx.values().getOrElse(ordinal, { _ -> defaultValue })
}
}
#Test fun testEnumOrdinals() {
val resultAdapter1 = Adapterx.fromOrdinal(0)
Assert.assertEquals(Adapterx.ADAPTER_1, resultAdapter1)
val resultAdapter2 = Adapterx.fromOrdinal(1)
Assert.assertEquals(Adapterx.ADAPTER_2, resultAdapter2)
// The following returns the default value ADAPTER_1
val resultOrdinalIndexOutOfBounds = Adapterx.fromOrdinal(2)
Assert.assertEquals(Adapterx.ADAPTER_1, resultOrdinalIndexOutOfBounds)
}
}

Kotlin: How to extend the enum class with an extension function

I'm trying to extend enum classes of type String with the following function but am unable to use it at the call site like so:
fun <T: Enum<String>> Class<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
return this.enumConstants
.drop(skipFirst)
.dropLast(skipLast)
.map { e -> e.name }
.joinToString()
}
MyStringEnum.join(1, 1);
What am I doing wrong here?
I suggest following solution:
fun <T : Enum<*>> KClass<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
return this.java
.enumConstants
.drop(skipFirst)
.dropLast(skipLast)
.map { e -> e.name }
.joinToString()
}
Instead of attaching extension function to Class, i attached it to KotlinClass.
Now, you can simply use it:
enum class Test {ONE, TWO, THREE }
fun main(args: Array<String>) {
println(Test::class.join())
}
// ONE, TWO, THREE
Use of ::class is a nasty workaround.
I suggest you to look at enumValues<E> and enumValueOf<E> from stdlib and do the same way:
inline fun <reified E : Enum<E>> joinValuesOf(skipFirst: Int = 0, skipLast: Int = 0): String =
enumValues<E>().join(skipFirst, skipLast)
#PublishedApi
internal fun Array<out Enum<*>>.join(skipFirst: Int, skipLast: Int): String =
asList()
.subList(skipFirst, size - skipLast)
.joinToString(transform = Enum<*>::name)
Usage: joinValuesOf<Thread.State>()
#IRus' answer is correct but you don't have to use reflection. For every enum class, a values() method is automatically generated by the compiler. This method returns an array containing all the entries. We can make the extension function operate directly on this array like this:
fun <T : Enum<*>> Array<T>.join(skipFirst: Int = 0, skipLast: Int = 0)
= drop(skipFirst)
.dropLast(skipLast)
.map { e -> e.name }
.joinToString()
And call it like this:
fun main(args: Array<String>) {
Test.values().join()
}
I'll rewrite your join slightly like this with a wildcard:
fun <T: Enum<*>> Class<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
return this.enumConstants
.drop(skipFirst)
.dropLast(skipLast)
.map { e -> e.name }
.joinToString()
}
Then, assuming your MyStringEnum is defined like this:
enum class MyStringEnum { FOO, BAR, BAZ }
You can call it like this:
println(MyStringEnum.values()[0].javaClass.join())
to get output "FOO, BAR, BAZ"
Since you're defining join on Class, you need an actual Class object to call it on. Enum classes apparently don't work like that, but its defined enums can yield a Class with javaClass. So this is the best I could come up with that I think meets the general spirit of your request. I don't know if there is a more elegant way to achieve what you're trying to do for all enum classes like this.
EDIT: You can tighten this up a little bit more with this:
fun Enum<*>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
return this.javaClass.join(skipFirst, skipLast)
}
Which lets you call like this:
println(MyStringEnum.values()[0].join())

When would you use an enum with associated values in preference to a static factory?

In Swift you can define an enum and give it a property via an associated value, e.g.:
protocol SizeEnum {
var length : Double? { get } // Length should be >= 0 - has to be an Optional for errors
}
enum SizesEnum : SizeEnum {
case Short(length : Double) // 0 <= length <= maxShort
case Long(length : Double) // length > maxShort
private static let maxShort = 1.0
var length : Double? {
get {
switch self {
case let .Short(length):
if length >= 0 && length <= SizesEnum.maxShort { // Need to error check every access
return length
}
case let .Long(length):
if length > SizesEnum.maxShort { // Need to error check every access
return length
}
}
return nil // There was an error
}
}
}
SizesEnum.Short(length: 0.5).length // [Some 0.5]
SizesEnum.Short(length: 2).length // nil
SizesEnum.Long(length: 2).length // [Some 2.0]
SizesEnum.Long(length: -1).length // nil
However this is not ideal because:
The error checking for the length parameter can only be done on access, you cannot intercept the init
The length parameter is surprisingly long winded
An alternative, which seems better to me, is to use a static factory, e.g.:
protocol SizeStruct {
var length : Double { get } // Length should be >= 0 - is *not* an Optional
}
struct SizesStruct : SizeStruct {
static func Short(length : Double) -> SizeStruct? {
if length >= 0 && length <= maxShort { // Check at creation only
return SizesStruct(length)
}
return nil
}
static func Long(length : Double) -> SizeStruct? {
if length > maxShort { // Check at creation only
return SizesStruct(length)
}
return nil
}
let length : Double
private static let maxShort = 1.0
private init(_ length : Double) {
self.length = length
}
}
SizesStruct.Short(0.5)?.length // [Some 0.5]
SizesStruct.Short(2)?.length // nil
SizesStruct.Long(2)?.length // [Some 2.0]
SizesStruct.Long(-1)?.length // nil
Given that the static factory solution is neater, when would I actually use an enum with values? Am I missing something? Is there a killer use case?
In response to drewag
For Optional other languages, e.g. Java and Scala, you use factories, the Java version is described here: http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html the factory is the of method.
In Swift you would do something like:
class Opt { // Note only Some stores the value, not None
//class let None = Opt() - class variables not supported in beta 4!
class Some<T> : Opt {
let value : T
init(_ value : T) {
self.value = value
}
}
private init() {} // Stop any other ways of making an Opt
}
Opt.Some(1).value // 1
This is probably the optimal example for enum since no error checking is required, but even so the factory version is competitive. The Optional example is so straightforward you don't even need a factory, you just create the Somes directly. Note how None doesn't use any storage.
The Barcode example shows how much better the factory technique is; in practice not all collections of 4 Ints are a valid UPCA and not all Strings are a valid QR Code, therefore you need error checking which is painful with enums. Here is the factory version:
class Barcode { // Note seperate storage for each case
class UPCABarcode : Barcode {
let type : Int, l : Int, r : Int, check : Int
private init(type : Int, l : Int, r : Int, check : Int) {
(self.type, self.l, self.r, self.check) = (type, l, r, check)
}
}
class func UPCA(#type : Int, l : Int, r : Int, check : Int) -> UPCABarcode? {
if ok(type: type, l: l, r: r, check: check) {
return UPCABarcode(type: type, l: l, r: r, check: check)
}
return nil
}
class func QRCode(#s : String) -> Barcode? { // Have not expanded this case; use same pattern as UPCA
return Barcode()
}
private init() {} // Prevent any other types of Barcode
class func ok(#type : Int, l : Int, r : Int, check : Int) -> Bool {
return true // In practice has to check supported type, range of L and R, and if check digit is correct
}
}
Barcode.UPCA(type: 0, l: 1, r: 2, check: 3)
If you use the enum version of Barcode then every time you use a Barcode you have to check its validity because there is nothing to stop invalid barcodes. Whereas the factory version does the checking at creation. Note how Barcode has no storage and UPCA has custom storage. I didn't code QRCode because it uses the same design pattern as UPCA.
My impression is that the enum version looks great in tutorials but soon becomes painful in practice because of error handling.
I believe the biggest killer use case is Optional. It is built into the language, but an optional is simply an enum:
enum Optional<T> {
case None
case Some(T)
}
In this case, a member variable like value would not make sense because in the None case, there is literally no value.
Also, right out of the Swift tour:
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
With a struct, there would be a lot of wasted member variables and a confusing interface to model this kind of data.
I don't believe it makes sense to use an associated value for an enum if the same type is used for every case. In that case a member variable is cleaner. The focus of associated values is to more accurately model certain types of data. The most useful cases are ones where different instances of a type can have different data associated with them. This could potentially be done with subclasses but then one would need to downcast to access more specific variables and the declarations would be much more verbose. Enums are a concise way to represent this type of data.
Another example could be web requests:
struct NetRequest {
enum Method {
case GET
case POST(String)
}
var URL: String
var method: Method
}
var getRequest = NetRequest(URL: "http://drewag.me", method: .GET)
var postRequest = NetRequest(URL: "http://drewag.me", method: .POST("{\"username\": \"drewag\"}"))
When I think of "enum" I don't think of "factory" at all. Normally factories are for larger more complex class structures. Enums are supposed to be very small pieces of data with little logic.

Resources