Retrieve kotlin annotations from java class - kotlin

I have an interface which has annotation:
#Target(AnnotationTarget.PROPERTY)
annotation class Foo()
interface Bah {
#Foo val prop: String
}
I'm implementing a jackson contextual deserializer, and I need to pick up this annotation from the methods in the interface.
override fun createContextual(ctxt: DeserializationContext, property: BeanProperty?): JsonDeserializer<*> {
val clzz = ctxt.contextualType.rawClass as Class<T>
for (method in clzz.methods) {
val anns = method.getAnnotationsByType(Foo::class.java)
ctxt.contextualType is a JavaType. I obtain clzz from it, which yields me a class of type Bah (i.e. the interface). I can iterate the methods, which include "prop"; however, prop has no annotations.
It DOES work if I modify the annotation site to look like this:
interface Bah {
val prop: String
#Foo() get
However, that's ugly. How can I modify things so that I can retrieve from the interface property directly?
Thanks

You can't. As the documentation says, annotations targeting a property are not visible from Java (because Java does not have the concept of properties).

Related

How to set serializer to an internal class extending a public interface?

I'm trying to create a serializer using kotlinx.serialization for Compose Desktop classes, I have this :
#Serializer(forClass = MutableState::class)
class MutableStateSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<MutableState<T>> {
override fun deserialize(decoder: Decoder) = mutableStateOf(decoder.decodeSerializableValue(dataSerializer))
override val descriptor: SerialDescriptor = dataSerializer.descriptor
override fun serialize(encoder: Encoder, value: MutableState<T>) = encoder.encodeSerializableValue(dataSerializer, value.value)
}
That should be used for instances of MutableState class (as the #Serializer annotation says), but I have to put an explicit serializer for each properties otherwise I get this error :
xception in thread "main" kotlinx.serialization.SerializationException: Class 'SnapshotMutableStateImpl' is not registered for polymorphic serialization in the scope of 'MutableState'.
Mark the base class as 'sealed' or register the serializer explicitly
Code used :
#Serializable
class Test {
var number = mutableStateOf(0)
}
fun main() {
val json = Json { prettyPrint = true }
val serialized = json.encodeToString(Test())
println(serialized)
}
I have to put this annotation on my property :
#Serializable(with = MutableStateSerializer::class)
Isn't there a way to automatically link my serializer to the MutableState interface ? As the SnapshotMutableStateImpl is internal I can't set it to this class.
What you want is currently not possible. Other people seem to have requested a feature similar to what you need on GitHub: Global Custom Serializers.
Currently, for 3rd party classes, you need to specify the serializer in one of three ways:
Pass the custom serializer to the encode/decode method in case you are serializing it as the root object.
Specify the serializer on the property using #Serializable, as you do now.
Specify the serializer to be used by a full file using #file:UseSerializers.
Note that due to type inference, number will be attempted to be serialized as the return type of mutableStateOf. If you specify the type as an interface instead (does it have a supertype?), using polymorphic serialization, you could try to register the concrete type and pass your custom serializer there for the concrete type. Not really what this feature is designed for, but I believe it may work if you don't want to specify your serializer in multiple places. However, the serialized form will then include a type discriminator everywhere.

#SerialInfo - How to manage user-defined serial annotations with Kotlinx serialization?

Kotlinx serialization documentation
According to Kotlinx.serialization user-defined annotations doc:
"Inside a process of serialization/deserialization, your own annotation class are available in SerialDescriptor object" :
override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
val annotations = desc.getElementAnnotations(index)
...
}
What I want to do
I need a #Transient equivalent, but conditional:
classic way where : Json.stringify(serializer, myClass) works as usual.
custom way where : Json.stringify(customSerializer, myClass) would return usual json but exculding all #MyAnnotation-tagged values.
Here is my code
#SerialInfo
#Target(AnnotationTarget.PROPERTY)
annotation class CustomAnnotation
#Serializable
data class MyClass(val a: String, #CustomAnnotation val b: Int = -1)
And I would like to build a custom Serializer and achieve something like
override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
val isTaggedAsCustomAnnotation = desc.getElementAnnotations(index).any{ it is CustomAnnotation }
val myCondition = mySerializer.getMyConditionBlablabla
if(myCondition && isTaggedAsCustomAnnotation) {
encode()
}
...
}
What I found
abstract class ElementValueEncoder : Encoder, CompositeEncoder {
...
open fun encodeElement(desc: SerialDescriptor, index: Int): Boolean = true
}
But I don't know how I can build a custom Serializer so that I can override that function Encoder.encodeElement. Where can I access to ElementValueEncoder in a custom Serializer ?
I also found this sample demo in kotlinx.serialization github repo. It's using TaggedEncoder & TaggedDecoder where I'm able to override encodeTaggedValue. But here again I don't know how I can use those encoder/decoder in a process of serialization/deserialization.
Finally
Where can I override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean, and how I can handle my own-defined serialization annotation ?
Thanks !!
First of all, you need to grasp the difference between Serializer and Encoder. Serializer (represented by KSerializer) defines how your class looks like, and Encoder (represented by e.g. JsonOutput) defines how data will be recorded. You can find more info on that topic here: https://github.com/Kotlin/KEEP/blob/master/proposals/extensions/serialization.md#core-api-overview-and-mental-model .
So, custom annotations feature is mainly used for providing format-specific information to Encoder. Typical usage of such an annotation is ProtoId – property id, specific to protobuf format, that should be recognized by ProtobufEncoder. Such annotations are usually defined by format authors alongside their encoders.
What you want to do here, as I can see, is to use already existing encoder (JSON format), so overriding encodeElement is impossible since Json encoders can not be subclassed. I'd advise you to use custom json transofrming serializer to achieve your goal. Unfortunately, currently kotlinx.serialization does not have mechanism to generalize such a transformation, so you need to write such serializer for each class.

How to filter data class properties by kotlin annotation?

Implimentation of Annotation
#Target(AnnotationTarget.PROPERTY)
#Retention(AnnotationRetention.RUNTIME)
annotation class Returnable
Dummy Data class
data class DataClass(
val property: String
#Returnable
val annotatedProperty: String
)
Java Reflections filtering doesn't work
this::class.memberProperties
.filter{ it.annotations.map { ann -> ann.annotationClass }.contains(Returnable::class)}
Kotlin annotation isn't the same as Java annotations. So work with Kotlin reflection requires a bit different way compare to classic java. Here you can find a way of filtering properties of Kotlin data class by Kotlin annotations
DataClass("false","true")::class.members.filter {
it.findAnnotation<Returnable>() != null
}

Getting class of lateinit property in Kotlin

Is it somehow possible to get ::class.java from Kotlin lateinit property before it is initialized?
Logically it should work - I'm trying to obtain a class not a value, but in reality it fails with uninitialized property access exception.
Note that the property I'm trying to get class of is in generic class and its type is one of generic parameters:
abstract class MVIFragment<
out INTERACTOR : MVIInteractor<UINTERFACE>,
UINTERFACE : MVIUIInterface,
MODEL : MVIViewModel
>
: Fragment(), MVIUIInterface, KodeinAware {
lateinit var viewModel: MODEL
I need the class to create an instance of ViewModel
viewModel = ViewModelProviders.of(this).get(viewModel::class.java)
Of course I can't do:
viewModel = ViewModelProviders.of(this).get(MODEL::class.java)
Any solution for that?
Due to type erasure, generic types are not known at runtime. That's just how Java/JVM works, and Kotlin doesn't attempt to magically work around it. (Unlike Scala, which has implicit magic which works magically, except when it doesn't.)
You will have to pass it along from some context where the type is statically determined, e.g.
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
}
Container(String::class.java)
You can use an inline function with reified types to hide this ugliness,
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
companion object {
inline operator fun <reified T : Any> invoke() = Container(T::class.java)
}
}
Container<String>()
which really compiles to the same thing. (The <String> can be omitted if type inference can determine it from context.)
In your case, it won't be possible to do this trick in the base (abstract) class; it has to be done on the concrete types.

What does 'by' keyword do in Kotlin?

While developing for android I sometimes come across something that looks like this:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
I don't understand what the significance of the by keyword is.
In simple words, you can understand by keyword as provided by.
From the perspective of property consumer, val is something that has getter (get) and var is something that has getter and setter (get, set). For each var property there is a default provider of get and set methods that we don't need to specify explicitly.
But, when using by keyword, you are stating that this getter/getter&setter is provided elsewhere (i.e. it's been delegated). It's provided by the function that comes after by.
So, instead of using this built-in get and set methods, you are delegating that job to some explicit function.
One very common example is the by lazy for lazy loading properties.
Also, if you are using dependency injection library like Koin, you'll see many properties defined like this:
var myRepository: MyRepository by inject() //inject is a function from Koin
In the class definition, it follows the same principle, it defines where some function is provided, but it can refer to any set of methods/properties, not just get and set.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
This code is saying:
'I am class MyClass and I offer functions of interface SomeInterface which are provided by SomeImplementation.
I'll implement SomeOtherInterface by myself (that's implicit, so no by there).'
In the Kotlin reference you will find two uses for by, the first being Delegated Properties which is the use you have above:
There are certain common kinds of properties, that, though we can implement them manually every time we need them, would be very nice to implement once and for all, and put into a library. Examples include lazy properties: the value gets computed only upon first access,
observable properties: listeners get notified about changes to this property,
storing properties in a map, not in separate field each.
Here you delegate the getter/setter to another class that does the work and can contain common code. As another example, some of the dependency injectors for Kotlin support this model by delegating the getter to receiving a value from a registry of instances managed by the dependency injection engine.
And Interface/Class delegation is the other use:
The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code. A class Derived can inherit from an interface Base and delegate all of its public methods to a specified object
Here you can delegate an interface to another implementation so the implementing class only needs to override what it wants to change, while the rest of the methods delegate back to a fuller implementation.
A live example would be the Klutter Readonly/Immutable collections where they really just delegate the specific collection interface to another class and then override anything that needs to be different in the readonly implementation. Saving a lot of work not having to manually delegate all of the other methods.
Both of these are covered by the Kotlin language reference, start there for base topics of the language.
The syntax is:
val/var <property name>: <Type> by <expression>.
The expression after by is the delegate
if we try to access the value of property p, in other words, if we call get() method of property p, the getValue() method of Delegate instance is invoked.
If we try to set the value of property p, in other words, if we call set() method of property p, the setValue() method of Delegate instance is invoked.
Delegation for property:
import kotlin.reflect.KProperty
class Delegate {
// for get() method, ref - a reference to the object from
// which property is read. prop - property
operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
// for set() method, 'v' stores the assigned value
operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property
#JvmStatic fun main(args: Array<String>) {
println(s)
s = "textB"
}
}
Result:
textA
value = textB
Delegation for class:
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
#JvmStatic fun main(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
Result:
property from ClassA
fun from ClassA
Delegation for parameters:
// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Int by mapA
var address: String by mapB
var id: Long by mapB
}
object SampleBy {
#JvmStatic fun main(args: Array<String>) {
val user = User(mapOf("name" to "John", "age" to 30),
mutableMapOf("address" to "city, street", "id" to 5000L))
println("name: ${user.name}; age: ${user.age}; " +
"address: ${user.address}; id: ${user.id}")
}
}
Result:
name: John; age: 30; address: city, street; id: 5000