In Kotlin, it's easy to pass a property as a KProperty or KProperty1 like this for example:
inline fun <TRet, reified TOwner> getName(property: KProperty1<TOwner, TRet>): String {
return "${TOwner::class.simpleName}.${property.name}"
}
And then given the following type:
class Example(val exampleName: String)
I could call getName(Example::exampleName) which would return Example.exampleName.
Is there any way to do this with enums?
Say I had the following enum class:
enum class ExampleEnum { VALUE1, VALUE2 }
Is there any way to get ExampleEnum::VALUE1 or some useful reflection object about the values in ExampleEnum? I essentially want to be able to access the declaring KClass (or java class) and the field being accessed in the enum, just by passing one argument.
The alternative is to write something like getName(ExampleEnum::class, "VALUE1") which is verbose and doesn't play well with refactorings/renames. Also, please note the getName is just an example, the actual use case is a bit more general.
Related
I'm trying to use inline classes in Kotlin to create a class inlining the String class, such that if I have an instance of my class that it will always be true for the contained string that s == s.trim().
I was initially expecting there to be a straightforward way to do this, like perhaps:
#JvmInline
value class Trimmed private constructor(val str: String) : {
constructor(s : String) : super(s.trim())
}
but that doesn't work, and neither do the other direct approaches I considered ("this(s.trim())", etc.).
This problem has turned out to be surprisingly tricky:
Kotlin seems to provide no easy way to have the primary constructor filter or modify the data that is passed to the constructor of the contained String object.
Even if I make the primary constructor private, I can't declare another constructor with the same signature (taking a single String as a parameter).
If this were a normal (non-inlined) class, I could just set the value after superclass class construction (e.g. "init { str = str.trim() }", but since it's an inline class, I can't do that. ("this=this.trim()" doesn't work either, and String objects themselves are immutable so I can't change the contents of 'str'.)
I tried making the class constructor private and creating a factory function in the same file with the same name as the class, but then I couldn't call the class constructor from within the factory function due to access restrictions.
I then tried making the factory function within the class's companion object, but then Kotlin tried to make that function call itself recursively instead of calling the class's constructor. I wasn't able to find a way to syntactially disambiguate this. I managed to work around this by creating a file-private typealias to give another name for the class so I could call the constructor from within the factory function. (Annoyingly, I couldn't declare the typealias in the companion object next to the factory function: I had to declare it outside.)
This worked, but seemed ugly:
typealias Trimmed2 = Trimmed
#JvmInline
value class Trimmed private constructor(val str: String) {
init { assert(str == str.trim()) }
companion object {
// Kotlin won't let me put the typealias here. :-(
fun Trimmed(s: String): Trimmed = Trimmed2(s.trim()) // Don't want recursion here!
}
}
Another working solution is here, using a private constructor with a dummy argument. Of course Kotlin complained that the dummy argument was unused and so I had to put in a big (why is it so big?) annotation suppressing the warning, which is, again, ugly:
#JvmInline
value class Trimmed private constructor(val str: String) {
private constructor (untrimmed: String, #Suppress("UNUSED_PARAMETER") dummy: Unit) : this(untrimmed.trim())
init { assert(str == str.trim()) }
companion object {
fun Trimmed(s: String): Trimmed = Trimmed(s, Unit)
}
}
Is there a simpler, cleaner way to do this? For instance, a syntactic way to clarify to Kotlin that the companion function is trying to call the class constructor and not itself and so avoid the need for a dummy parameter?
Goals:
Code to construct instances of the class from outside this file should look like constructing an instance of a normal class: 'Trimmed("abc")', not using some factory function with a different name (e.g. "of" or "trimmedOf") or other alternate syntax.
It should be impossible to construct the object containing an untrimmed string. Outside code, and the Trimmed class itself, should be able to trust that if a Trimmed instance exists, that its contained str will be a trimmed string.
I am still learning kotlin, and I am curious how is it possible that mockk is able to return some object T wrapped in Result<T>. For better understanding let analyse below example:
We have such method definition
fun save(toSave : Entity): Result<Entity>
when we mock such method using returnArguments like it is done below:
every { mocked.save(any()) } returnsArgument 0
Then method returns Result<Entity>, but logic says that Entity should be returned.
Looking into declaration of returnsArgument there is casting to generic type which in our case is Result<Entity>, but when I tried to do it in plain I had casting exception.
I assume some magic happens inside, but what magic is responsible for such thing?
Would it be done with any wrapping object or it is specific only to Result?
Result<T> is a value class and mockk has a value class support.
After many internal steps returnsArgument will wrap the argument n with the specified value class and will return it.
Would it be done with any wrapping object or it is specific only to Result?
All value classes are supported, not just Result<T>.
// supported
#JvmInline
value class ValueWrapper<out T> (val something: Any?)
// not supported
class SomeWrapper<out T> (val something: Any?)
Hope it helps.
So, as is well-known, Kotlin is able to access Java libraries, and among them is the BigInteger class. And this class has a very handy feature: There is a keyword, called "BigInteger.ZERO", which returns a BigInteger object whose value equals zero.
Now I am writing a fraction data type, and I'd very much like to do the same thing for it. But the problem with just putting a val inside the class is that this first needs an object to begin with; it's not a "static" constant, so to say.
I'd be very grateful indeed for any forthcoming replies.
You can put the constant as a val inside the companion object of your class:
class Fraction {
...
companion object {
val ZERO = Fraction()
}
}
Then you can call your constant by Fraction.ZERO.
Note that this only makes sense if your fraction class is immutable.
I know how to get an annotation of an enum value in Java.
However Kotlin has its own reflection library and I feel there should be a better way to do the job.
Could please anybody post an example.
Just to be specific let's define an enum class
enum class Enum {
#SerialName("constant")
Constant
}
I need a function f(e: Enum): String so that f(Enum.Constant) == "constant".
You can use a similar approach with java by getting the field by name and then reaching out to the annotation using annotation class.
So if you have below enum and annotation class definitions;
enum class Enum {
#SerialName("constant")
Constant
}
annotation class SerialName(val value: String)
Then you can define the below function and call it as shown below;
fun getAnnotationValue(enum:Enum):String = enum.declaringClass.getField(enum.name).getAnnotation(SerialName::class.java).value
fun main(args: Array<String>) {
println(getAnnotationValue(Enum.Constant))
}
Hope this helps.
I did only a little research here, but it appears there isn't support for this in the Kotlin reflection library. In fact, I discovered the linter doesn't even correctly suggest an annotation target of FIELD for your annotation if you give it one that doesn't work for Enum values, and instead incorrectly offers to automatically add a target of CLASS.
The problem is that Enum values are basically static member fields, which don't exist in Kotlin except in Enum classes. And the reflection classes don't seem to provide a way to access this special case.
I am struggling however to come up with a use case for Enum value annotations that can't be solved using properties in the Enum constructor(s).
enum class MyEnum(val someConstant: String? = null) {
SomeValue("myConstant")
}
Given:
enum class Foo {
BAR,
BAZ { fun qux(foo: Any) {} }
}
It appears to be legal code, but when I try to access qux() like so:
val foo = Foo.BAZ
foo.qux("blah")
...it doesn't work as the member function is not visible.
Is there a way I can access qux() outside of the enum class? If not, then what would be a use case for a custom member of an enum entry?
You can use it to implement interfaces and abstract methods, but since those body blocks are anonymous classes You won't be able to explicitly access per-entry values.
Perhaps what you're looking for can be achieved by using sealed classes?