I have an enum of regions like this:
enum class Regions(val location:String){
REGION_1("London"),
}
Is there a way to access the properties of region_1 with just a string like in the below function?
fun access(name:String){
return Regions.<modifed_name>.location
}
You can convert your string to enum using valueOf(value: string) and then use the location
fun access(name:String): String = Regions.valueOf(name.uppercase()).location
enum class Regions(val location: String) {
REGION_1("London"),
REGION_2("Berlin"),
REGION_3("Pairs")
}
fun access(name:String): String {
return Regions.values().firstOrNull() { it.name == name }?.location ?: "location not found"
}
println(access("REGION")) // Output: location not found
println(access("REGION_2")) // Output: Berlin
Related
I'm trying to test a private method which takes the below parameters as input :
ClassToBeTested
delete(
someId1: String,
aList: List<CustomObject>,
someId2: String,
someId3: String,
someId4: String
) : Long? {
}
TestClass
val method = ClassToBeTested.javaClass.getDeclaredMethod("delete", String::class.java,
List::class.java, String::class.java, String::class.java, String::class.java)
method.isAccessible = true
val testId = method.invoke(ClassToBeTested, someId1, aList, someId2, someId3, someId4)
I end up getting the below error :
java.lang.NoSuchMethodException:
ClassToBeTested$Companion.delete(java.lang.String, java.util.Arrays$ArrayList, java.lang.String, java.lang.String, java.lang.String)
When I tried changing the above method declaration as :
val method = ClassToBeTested.javaClass.getDeclaredMethod("delete", String::class.java,
List<CustomObject>::class.java, String::class.java, String::class.java, String::class.java)
I get the below error :
Kotlin: Only classes are allowed on the left hand side of a class literal
Is there anyway we can test the private function which takes a parameter of List of Custom Objects?
Don't use reflection for this. Simply make the method internal and call it directly from your tests. You can even add an annotation like #VisibleForTesting or #TestOnly, those are available in various libraries.
You can use Kotlin's declaredMemberFunctions property to find it based on its name alone:
data class CustomObject(val id: String)
class ClassToBeTested {
private fun delete(
someId1: String,
aList: List<CustomObject>,
someId2: String,
someId3: String,
someId4: String
): Long? {
return someId1.toLongOrNull()
}
}
class SampleTest {
#Test
fun test1() {
val instance = ClassToBeTested()
val method = instance::class.declaredMemberFunctions.first { it.name == "delete" }.apply { isAccessible = true }
val result = method.call(instance, "1", emptyList<CustomObject>(), "2", "3", "4")
assertEquals(1L, result)
}
}
I have an enum class which maps language locale to a list.
How can I fix the function getReservationFrequencies inside the companion object
to return the value of the map based on the locale (key)?
enum class ReservationFrequencies(val frequencies: Map<Language, List<ReservationFrequency>>) {
APPLICATION(mapOf(
Language.en to listOf(
ReservationFrequency(0,"once",0),
ReservationFrequency(1,"Monthly",2),
ReservationFrequency(2,"Quarterly",5),
ReservationFrequency(3,"Semi-annually",5),
ReservationFrequency(4,"Annually",5)
),
Language.ar to listOf(
ReservationFrequency(0,"مرة واحده",0),
ReservationFrequency(1,"شهرياً",2),
ReservationFrequency(2,"ربع سنوياً",5),
ReservationFrequency(3,"نصف سنوياً",5),
ReservationFrequency(4," سنوياً",5)
)
));
}
I tried creating a companion object that includes a function that returns the list
companion object {
fun getReservationFrequencies(locale: String?) : List<ReservationFrequency> {
val reservationFrequencyDtos = mutableListOf<ReservationFrequency>()
reservationFrequencies.values()
.filter { locale!!.contains(it.name)}
.forEach() {
ReservationFrequency.add(ReservationFrequency(code = it.frequencies))
}
}
}
I'm expecting a List<ReservationFrequency> based on the locale
Probably just this
fun getReservationFrequencies(locale: String?) : List<ReservationFrequency> =
ReservationFrequencies.APPLICATION.frequencies.filter {
it.key.name == locale // I don't know the specifics of how to match the String locale arg against Language
}.map {
it.value
}.first()
I've got a stupid question that stunned me a bit.
I have an enum and a data class like this:
enum class MyEventType(val typeName: String) {
FIRST("firstEventReceived")
}
data class MyEvent(
val id: String,
val event: MyEventType
)
I need to send this as a json string, but common desearilizer makes such a json
{
"id": "identifier",
"event": "FIRST"
}
but i need
{
"id": "identifier",
"event": "firstEventReceived"
}
As far as i understand, kotlin allows to override getter in data class, but i didn't succeed in it... Trying to make
data class MyEvent(
val id: String
) {
val event: MyEventType get() event.typeName
}
but i've missed something, i guess...
The simplest way is probably to annotate the property with #JsonValue:
enum class MyEventType(#JsonValue val typeName: String) {
FIRST("firstEventReceived")
}
data class MyEvent(
val id: String,
val event: MyEventType
)
fun main() {
MyEvent(id = "foo", event = MyEventType.FIRST)
.let { jacksonObjectMapper().writeValueAsString(it) }
.let { println(it) }
}
Prints:
{"id":"foo","event":"firstEventReceived"}
The easiest way is to annotate the typeName with #JsonValue. This will serialise and deserialise the enum field as you want.
enum class MyEventType(#JsonValue val typeName: String) {
FIRST("firstEventReceived");
}
An alternative is to use #JsonFormat (if you are using jackson version < 2.9);
enum class MyEventType(#JsonFormat(shape = JsonFormat.Shape.OBJECT) val typeName: String) {
FIRST("firstEventReceived");
}
Herer's an example;
#JvmStatic
fun main(args: Array<String>) {
val mapper = jacksonObjectMapper()
val json = mapper.writeValueAsString(MyEvent("1", MyEventType.FIRST))
println(json)
val event = mapper.readValue<MyEvent>(json)
println(event)
}
You get the output;
{"id":"1","event":"firstEventReceived"}
MyEvent(id=1, event=FIRST)
I used Jackson version 2.12.0. Here's a good read on enum manipulation with Jackson - https://www.baeldung.com/jackson-serialize-enums
Also you can have enum with 2+ fields which you want to be serialized
enum class MyEventType(
val firstField: String,
val secondField: String,
val thirdField: String
) {
MY_ENUM("firstFieldValue", "secondFieldValue", "thirdFieldValue")
}
You can chose one of the following two options:
Put #JsonValue over a method(lets call it getter) that will return the required value(if you need only part of the fields):
#JsonValue
fun getSerializedObject(): String {
return "{firstField: $firstField, thirdField: $thirdField}"
}
Result will be "{firstField: firstFieldValue, thirdField: thirdFieldValue}"
Put #JsonFormat(shape = JsonFormat.Shape.OBJECT) over your enum class(for serialization class as common class):
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
enum class MyEventType(
val firstField: String,
val secondField: String,
val thirdField: String
) {
MY_ENUM("firstField", "secondField", "thirdField")
}
Result will be "{"firstField": "firstFieldValue", "secondField": "secondFieldValue", "thirdField": "thirdFieldValue"}"
For GSON users, you can use the #SerializedName annotation:
enum class ConnectionStatus {
#SerializedName("open")
OPEN,
#SerializedName("connecting")
CONNECTING,
#SerializedName("closed")
CLOSED
}
In Kotlin I have an enum as follows:
enum class MediaType() {
AUDIO,
VIDEO,
ARTICLE;
}
I would like to add either a function or some property that allows an enum member to be converted to some corresponding text. For example:
var mediaType = MediaType.AUDIO
var text = mediaType.toText() // returns the string "MP3"
mediaType = MediaType.VIDEO
text = mediaType.toText() // returns the string "mpeg"
While I can add the toText function to the MediaType class, I am not sure how that function references the value it is set to.
You can add a property to the enum...
enum class MediaType(val text: String) {
AUDIO("mp3"),
VIDEO("mpeg"),
ARTICLE("text");
}
And then use it like this:
println(MediaType.AUDIO.text)
If you'd like a toText() function rather than a property, that can be added as well, but probably isn't as idiomatic:
enum class MediaType(private val text: String) {
AUDIO("mp3"),
VIDEO("mpeg"),
ARTICLE("text");
fun toText(): String = text
}
Update:
Another way is to add an extension function and keep this logic outside the enum entirely:
fun MediaType.toText(): String =
when(this) {
MediaType.AUDIO -> "mp3"
MediaType.VIDEO -> "mpeg"
MediaType.ARTICLE -> "text"
}
enum class MediaType() {
AUDIO,
VIDEO,
ARTICLE;
fun getMemberText() = when (this) {
AUDIO -> "mp3"
VIDEO -> "mpeg"
else -> "text"
}
}
Why there is no contains method in enum classes (as well as in Java)? And how to implement it elegantly? Now I'm using this ugly approach:
val contains: Boolean =
try {
MyEnum.valueOf("some string")
true
} catch (e: IllegalArgumentException) {
false
}
enumContains
You can create an enumContains function similar to Hound Dog's answer but using reified type parameters instead.
You cannot create a JVM independent solution in Kotlin 1.0 but you can in Kotlin 1.1 using enumValues.
Kotlin 1.1
/**
* Returns `true` if enum T contains an entry with the specified name.
*/
inline fun <reified T : Enum<T>> enumContains(name: String): Boolean {
return enumValues<T>().any { it.name == name}
}
Kotlin 1.0
/**
* Returns `true` if enum T contains an entry with the specified name.
*/
inline fun <reified T : Enum<T>> enumContains(name: String): Boolean {
return T::class.java.enumConstants.any { it.name == name}
}
Usage
enumContains<MyEnum>("some string") // returns true or false
enumValueOfOrNull
If you also need the actual enum entry then you might consider creating an enumValueOfOrNull function instead.
Kotlin 1.1
/**
* Returns an enum entry with the specified name or `null` if no such entry was found.
*/
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
return enumValues<T>().find { it.name == name }
}
Kotlin 1.0
/**
* Returns an enum entry with the specified name or `null` if no such entry was found.
*/
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
return T::class.java.enumConstants.find { it.name == name }
}
Usage
enumValueOfOrNull<MyEnum>("some string")
You can just take values Array of your enum and use contains over it. For example:
Planets.values().map { it.name }.contains("EARTH")
But for this you need to have correct string value so you might uppercase it before search.
If you want to find enum by its value take a look at the Reverse Lookup for enums.
Edit:
As #JamesBassett suggested you can optimize it to stop looking once it finds a match.
Planets.values().any { it.name == "EARTH" }
You could do something like this:
fun <T : Enum<*>> KClass<T>.contains(value: String): Boolean {
return this.java.enumConstants.any { it.name == value }
}
MyEnum::class.contains("some string")
or if you are really adventurous
enum MyEnum {
MY_1, MY_2;
companion object {
fun isInEnum(someString: String) {
return try {
valueOf(someString)
true
} catch (e: Exception) {
false
}
}
}
}