Kotlin get Field Annotation always empty - reflection

I have the following Kotlin Annotation
#Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY_GETTER)
#Retention(AnnotationRetention.RUNTIME)
annotation class Field(val value: String)
And the following Test Code
class TestObject(#field:Field("id") val id: Long) {
#field:Field("string")
val string = "Hello world"
#get:Field("prop")
val prop get() = string
}
class AnnotationTest {
#Test
fun test() {
val obj = TestObject(200L)
for (member in obj::class.declaredMemberProperties) {
if (member.findAnnotation<Field>() != null) {
println(member)
}
println(member)
println(member.annotations)
}
println("#########")
for(member in obj.javaClass.declaredFields) {
println(member)
println(member.annotations)
}
}
}
It will print the following Output:
val TestObject.id: kotlin.Long
[]
val TestObject.prop: kotlin.String
[]
val TestObject.string: kotlin.String
[]
#########
private final java.lang.String TestObject.string
[Ljava.lang.annotation.Annotation;#33d512c1
private final long TestObject.id
[Ljava.lang.annotation.Annotation;#515c6049
Why I can't see the Annotation with Kotlin reflection? Need to find out if the given annotation is present on fields and property getters.

Your annotation for prop is targeting getter, instead of calling findAnnotation on the property, you have to call it on the getter of the property.
for (member in obj::class.declaredMemberProperties) {
if (member.getter.findAnnotation<Field>() != null) { //add .getter
println(member)
}
println(member)
println(member.getter.annotations) //add .getter
}
Your annotation for id and string is targeting field, so what you did in the second loop is correct. Since member.annotations returns Annotation[], you have to change it to a List before printing it.
for(member in obj.javaClass.declaredFields) {
println(member)
println(member.annotations.toList()) //Add .toList()
}
Output:
val TestObject.id: kotlin.Long
[]
val TestObject.prop: kotlin.String
val TestObject.prop: kotlin.String
[#Field(value=[prop])]
val TestObject.string: kotlin.String
[]
#########
private final java.lang.String TestObject.string
[#Field(value=[string])]
private final long TestObject.id
[#Field(value=[id])]

Related

Cannot fill a MutableLiveData of type ArrayList, outcome is always null

Im working on a quizgame and i want to store some ids in a MutableLiveData-arraylist. Therfore i made a function to loop all my documents in de database and add each ID to the arraylist. BUT the outcome is always null. I don't see where i go wrong?
I'm working with a MVVM-structure
GameViewModel:
class GameViewModel : ViewModel() {
// database instance
val db = FirebaseFirestore.getInstance()
// the current category
private val _category = MutableLiveData<String>()
val category: LiveData<String>
get() = _category
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>()
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
// the current question
private val _question = MutableLiveData<String>()
val question: LiveData<String>
get() = _question
/**
* Set Current Category
*/
fun SetCategory (categoryName: String){
_category.value = categoryName
}
/**
* Get the list of QuestionIds
*/
fun GetListQuestionIds() {
db.collection("questions")
.whereEqualTo("category", "$_category")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
_questionIdsArray.value?.add(document.data["questionid"] as Long)
Log.d("GetSize","${_questionIdsArray.value?.size}")
}
Log.d("GetSize2","${_questionIdsArray.value?.size}")
}
.addOnFailureListener { exception ->
Log.w("errorforloop", "Error getting documents: ", exception)
}
}
/**
* Get a Question
*/
fun GetQuizQuestion() {
Log.d("retro","${_questionIdsArray.value?.size}")
db.collection("questions")
.whereEqualTo("category", "$_category")
.whereEqualTo("questionid", "${_questionIdsArray.value?.get(0)}")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
_question.value = document.data["question"].toString()
}
}
.addOnFailureListener { exception ->
Log.w("err", "Error getting documents: ", exception)
}
}
GAMEFRAGMENT:
class GameFragment : Fragment() {
private lateinit var viewModel: GameViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentGameBinding.inflate(inflater)
// Get the viewModel
viewModel = ViewModelProvider(this).get(GameViewModel::class.java)
binding.lifecycleOwner = this
// Set the viewModel for DataBinding - this allows the bound layout access to all of the data in the VieWModel
binding.gameviewModel = viewModel
//arguments passed
val selectedCategory = arguments?.getString("selectedCategory")!!
//set current category so that the viewModel can use it
viewModel.SetCategory(selectedCategory)
viewModel.GetListQuestionIds()
viewModel.GetQuizQuestion()
return binding.root
}
If someone can enlighten me ...
Your Problem
You're not initializing the array. This is your code:
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>()
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
This declares a MutableLiveData of type ArrayList<Long>, but does not initialize it so its value defaults to null.
In your for loop you conditionally add items:
_questionIdsArray.value?.add(document.data["questionid"] as Long)
But of course value was never initialized so it's null so add is no-op (does nothing).
The Solution
Just ensure you initialize the live data object at some point.
You could do this inline in the declaration:
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>(arrayListOf())
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
Or during your attempt to populate the list:
.addOnSuccessListener { documents ->
val idsArray = arrayListOf<Long>() // Non-null list to add to
for (document in documents) {
idsArray.add(document.data["questionid"] as Long)
Log.d("GetSize","${idsArray.size}")
}
_questionIdsArray.value = idsArray // Now set live data with a valid list
Log.d("GetSize2","${_questionIdsArray.value?.size}")
}

When using Kotlin Exposed, how do I handle missing values for numbers in an sqlite database?

I have an sqlite data base that entries similar this example:
0|some_text0|123.456||some_other_text0
1|some_text1||456.789|some_other_text1
So as you can see the 3rd and 4th column are numbers, but in some records the data in the column is empty.
I defined the interface using something similar to this example.
object Foos : IntIdTable("foos") {
val sequelId = integer("id").primaryKey()
val text0 = text("text0")
val num0 = float("num0").nullable()
val num1 = float("num1").nullable()
val text1 = text("text1")
}
class Foo(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Foo>(Foos)
var sequelId by Foos.sequelId
var text0 by Foos.text0
var num0 by Foos.num0
var num1 by Foos.num1
var text1 by Foos.text
}
If I query a record that contains a missing value and try to access the field I throw an exception such as java.lang.String cannot be cast to java.math.Float?
for example:
val x = queryResult0.num1 //fails
I can get passed this via:
val x = try { queryResult0.num1 } catch(e: Exception) { null } // works I get a value or null
My current "hacky" solution is to add a second set of getters for the fields such this:
class Foo(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Foo>(Foos)
var sequelId by PinTimings.sequelId
var text0 by Foos.text0
var num0 by Foos.num0
var num1 by Foos.num1
var text1 by Foos.text
val num0x : Float?
get() = try { num0 } catch(e: Exception) { null }
val num1x : Float?
get() = try { num1 } catch(e: Exception) { null }
}
Then queryResut0.num1x provides what I need.
What's the right way to handle this kind of situation?
FYI: I am using the following setup
Kotlin: 1.2.61
Exposed: org.jetbrains.exposed:exposed:0.17.7
JDBC: org.xerial:sqlite-jdbc:3.32.3.2

Get Enum value by reflection in Kotlin

How would you rewrite the following Java code in Kotlin?
#SuppressWarnings({ "unchecked", "rawtypes" })
static Object getEnumValue(String enumClassName, String enumValue) throws ClassNotFoundException {
Class<Enum> enumClz = (Class<Enum>)Class.forName(enumClassName);
return Enum.valueOf(enumClz, enumValue);
}
The problematic line is Enum.valueOf(enumClz, enumValue)
The automatic conversion from IntelliJ IDE/Android Studio yields the following Enum.valueOf<Enum>(enumClz, enumValue), however there's no such method Enum.valueOf in Kotlin.
Forcing Kotling to use java.lang.Enum: java.lang.Enum.valueOf<Enum>(enumClz, enumValue). Compile error on the generic binding One type argument expected for class Enum<E: Enum<E>>.
Adding the type argument as java.lang.Enum.valueOf<Enum<*>>(enumClz, enumValue) yields a different error: Type argument is not within its bounds. Expected: Enum<Enum<*>!>! Found: Enum<*>.
You could do this in following way, of course you should probably do some additional checks for passed parameters but this should be what you are looking for:
fun getEnumValue(enumClassName: String, enumValue: String): Any {
val enumClz = Class.forName(enumClassName).enumConstants as Array<Enum<*>>
return enumClz.first { it.name == enumValue }
}
Also there is enumValueOf function but there you need to know actual enum type so not sure it helps, anyway here is how you could use that:
enum class SomeEnum{
FIRST, SECOND
}
val enumMember = enumValueOf<SomeEnum>("FIRST")
The best way I have found is to create an interface for the enums, converting them in typed enums:
/**
* Allow to search enums by type
*/
interface TypedEnum<T> {
fun value(): T
companion object {
/**
* Get the value of a typed enum
* #param enumValues array - You can get it with Enum.values()
* #param enumValue to search
* #param defaultValue to return if not found
* #return enum type or default value if not found or first enum value if default value not set
*/
fun <T, E : TypedEnum<T>> getEnumValue(enumValues: Array<E>, enumValue: T, defaultValue: E? = null): E {
try {
return enumValues.first { it.value()?.equals(enumValue) ?: false}
} catch (nsee: NoSuchElementException) {
// Log.e("TYPED_ENUM", "Exception converting value to enum type: $nsee")
}
return defaultValue ?: enumValues.first()
}
}
}
enum class TypeInt: TypedEnum<Int> {
TYPE_1 { override fun value() = 1 },
TYPE_2 { override fun value() = 2 },
TYPE_3 { override fun value() = 3 },
}
enum class TypeString: TypedEnum<String> {
TYPE_1 { override fun value() = "1" },
TYPE_2 { override fun value() = "2" },
TYPE_3 { override fun value() = "3" },
}
#Test
fun getEnumValue_valueExistInt() {
val value = TypedEnum.getEnumValue(TypeInt.values(), 2)
assertEquals(TypeInt.TYPE_2, value)
}
#Test
fun getEnumValue_valueExistString() {
val value = TypedEnum.getEnumValue(TypeString.values(), "2")
assertEquals(TypeString.TYPE_2, value)
}
#Test
fun getEnumValue_valueNotExist() {
val value = TypedEnum.getEnumValue(TypeInt.values(), 0)
assertEquals(TypeInt.TYPE_1, value)
}
#Test
fun getEnumValue_valueNotExistReturnDefault() {
val value = TypedEnum.getEnumValue(TypeInt.values(), 0, TypeInt.TYPE_3)
assertEquals(TypeInt.TYPE_3, value)
}
It is not the most elegant way, but it works. If I find a better solution I update this message.

Check that the class implements the interface. Kotlin

I want check that the child class of SignalPayload implements the interface IConvertible. How can I do that?
sealed class SignalPayload {
companion object {
fun trueTypeInstance(type: KClass<SignalPayload>) : SignalPayload? {
// if (*** __ KClass<SignalPayload> implemented IConvertible ___ **)
......
}
}
}
object Empty : SignalPayload()
data class BadData(val message: String = "BAD") : SignalPayload() {
override fun toString(): String {
return message
}
}
data class payloadString(private var payload: String = "") : SignalPayload(), IConvertible
data class payloadInt(private var payload: Int = 0) : SignalPayload(), IConvertible
data class payloadFloat(private var payload: Float = 0F) : SignalPayload(), IConvertible
data class payloadBool(private var payload: Boolean = false) : SignalPayload(), IConvertible
interface IConvertible {
val asBool: Boolean
val asInt: Int
val asFloat: Float
val asString: String
fun setFromPayload(data: IConvertible)
}
How can I do that?
UPD
That I had think use it.
Class SignalChannel know what field mPayload needed (through property val type: ???). At first mPayload equal Empty
interface IArriving {
fun onNewPayload(data: SignalPayload, sender: IArriving?)
}
interface IConvertible {
val asBool: Boolean
val asInt: Int
val asFloat: Float
val asString: String
fun setFromPayload(data: IConvertible)
}
class SignalChannel(val idx: Int, val type: ???, val name: String = "") : IArriving {
var mPayload: SignalPayload = Empty
// when new data arriving - need converting for `type` and refresh field mPayload
override fun onNewPayload(data: SignalPayload, sender: IArriving?) {
if ( mPayload is Empty ) {
mPayload = SignalPayload.trueTypeInstance(type) // that's my problem
}
mPayload.setFromPayload(data)
}
}
You could make use of proper generics in order to confine the method to types that are both SignalPayload and IConverible:
fun <T> trueTypeInstance(): SignalPayload?
where T : IConvertible, T : SignalPayload {
TODO()
}
Called like this:
SignalPayload.trueTypeInstance<payloadString>() //OK
SignalPayload.trueTypeInstance<Empty>() //Fails
SignalPayload.trueTypeInstance<String>() //Fails
Not sure about your use case though...

How can I get the name of a Kotlin property?

I have the following function to access a property's delegate. It uses Kotlin reflection to get a property's name and Java reflection to get the field.
fun Any.getDelegate<T>(prop: KProperty<T>): Any {
return javaClass.getDeclaredField("${prop.name}\$delegate").let {
it.setAccessible(true)
it.get(this)
}
}
The method is used like this:
val delegate = a.getDelegate(A::b)
However, I would prefer to use it like this:
val delegate = a.b.delegate
The problem with the code above is getting the property name of a.b and getting the instance a from a.b. From what I know about Kotlin, this is probably not possible, however I'd like to see if I can clean up my function at all.
To give a bigger picture of what I'm trying do here's my complete code. I want an observable delegate to which I can add and remove observers using the delegate reference and without creating addition variables.
fun Any.addObservable<T>(prop: KProperty<T>, observer: (T) -> Unit) {
getObservableProperty(prop).observers.add(observer)
}
fun Any.getObservableProperty<T>(prop: KProperty<T>): ObservableProperty<T> {
return getDelegate(prop) as ObservableProperty<T>
}
fun Any.getDelegate<T>(prop: KProperty<T>): Any {
return javaClass.getDeclaredField("${prop.name}\$delegate").let {
it.setAccessible(true)
it.get(this)
}
}
class ObservableProperty<T>(
initialValue: T,
initialObservers: Array<(T) -> Unit> = emptyArray()) : ReadWriteProperty<Any?, T> {
private var value = initialValue
public val observers: MutableSet<(T) -> Unit> = initialObservers.toHashSet()
public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
return value
}
public override fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
this.value = value
observers.forEach { it(value) }
}
}
class A() {
var b by ObservableProperty(0)
}
fun main(args: Array<String>) {
val a = A()
a.addObservable(A::b) {
println("b is now $it")
}
a.b = 1
a.b = 2
a.b = 3
}
Edit:
I just realized that the function also isn't strict because the property delegate field name is referenced by KProperty name, which doesn't require a strong reference to the enclosing class. Here's an example to demonstrate the problem:
class A() {
var foo by ObservableProperty(0)
}
class B() {
var foo by ObservableProperty(0)
}
fun main(args: Array<String>) {
val a = A()
a.addObservable(B::foo) {
println("b is now $it")
}
a.foo = 1
a.foo = 2
a.foo = 3
}
This compiles and runs without error because A::foo and B::foo both result in a field string of "foo$delegate.
Right now reflection is all we can do to get to the delegate object. We are designing a language feature to have direct access to delegate instance, but it's long way to go.
This is how you get the name of a Kotlin Property (although only with an instance of the class). This part will be useful to anyone arriving at this question purely based off its title.
class Stuff(val thing: String)
val stuff = Stuff("cool stuff")
val thingFieldName = "${stuff.thing}\$delegate"
// value of thingFieldName is now "thing"
In terms of getting the delegate itself easier, they say you can now do this:
class Foo {
var bar: String by ReactiveProperty<String>()
}
val foo = Foo()
val bar = foo.bar
val barDelegate = ... // foo.bar$delegate
See ticket.

Resources