Kotlin annotation only for annotation parameters - kotlin

I'd like to have a Kotlin annotation that can only be used as a parameter on another annotation. Which target should I use for it?
// #Target <- ?
annotation class MyConfigurationEntry(
val option,
val value
)
#Target(AnnotationTarget.FUNCTION)
annotation class MyConfiguration(vararg val entries: MyConfigurationEntry)

I believe it is #Target(AnnotationTarget.ANNOTATION_CLASS) if you click on that constant you will read:
Annotation class only
Kotlin version 1.3.41

Related

How to add annotation on main constructor parameters in kotlin

Having the following class:
data class TestMsg(
#Parse(";")
val someArray: Array<String>
)
And trying to get the annotation with
TestMsg::class.primaryConstructor!!.parameters.forEach{
println(it.findAnnotation<Parse>())
}
There is no annotation found. I had to move the annotation front of the parameter for make it working
data class TestMsg(
#Parse(";") val someArray: Array<String>
)
is it a parsing error of jetbrains or is it the normal behavior?
EDIT
You can find the annotation right here:
#Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.TYPE_PARAMETER)
#Retention(AnnotationRetention.RUNTIME)
annotation class Parse(
val delimiter: String
)
change AnnotationTarget.PROPERTY to AnnotationTarget.VALUE_PARAMETER
#Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE_PARAMETER)
#Retention(AnnotationRetention.RUNTIME)
annotation class Parse(
val delimiter: String
)

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
}

Dagger2 - How to use #Named with #BindsInstance

How is #Named used with #BindsInstance? I have the this component
interface AppComponent : AndroidInjector<MyApplication>{
#Component.Builder
abstract class Builder : AndroidInjector.Builder<MyApplication>() {
#BindsInstance
abstract fun preferenceName( #Named("PreferenceName") name : String ) : Builder
}
}
and trying to inject in MyApplication
#Inject
#Named("PreferenceName")
lateinit var prefName : String
But it fails with MissingBinding for String. I could resolve this with a module provider but trying to avoid provider for constants.
Update: Dagger 2.25.2 has eliminated the need for workaround:
Kotlin support
ii. Qualifier annotations on fields can now be understood without
The need for #field:MyQualifier (646e033)
iii. #Module object classes no longer need #JvmStatic on the
provides methods. (0da2180)
This doesn't have anything to do with #BindsInstance, but rather the #Named annotations on fields. You can tell from the "MissingBinding for String", which would otherwise give you an error about a Named string.
As in Svetlozar Kostadinov's article Correct usage of Dagger 2 #Named annotation in Kotlin, you'll need to clarify to Kotlin that you'd like the annotations to apply to the field.
#field:[Inject Named("PreferenceName")]
lateinit var prefName : String;
As Svetlozar puts it:
The reason is because in Kotlin annotations need to be slightly more complicated in order to work as expected from Java perspective. That’s coming from the fact that one Kotlin element may be a facade of multiple Java elements emitted in the bytecode. For example a Kotlin property is a facade of an underlying Java member variable, a getter and a setter. You annotate the property but what Dagger expects to be annotated is the underlying field.
Related: Dagger 2 constructor injection in kotlin with Named arguments

Kotlin parcelize issue with gson

I am using #parcelize for gson
Here is my class
#Parcelize
data class CommunityModel(#SerializedName("post") val post: PostModel,
#SerializedName("is_liked") val isLiked: Boolean,
#SerializedName("post_like") val postLike: QuestionModel,
#SerializedName("polling_options") val pollingOptions: List<PollingModel>,
#SerializedName("post_polled") val postPolled: Boolean) : Parcelable
I got error Unable to invoke no-args constructor for class. Register an InstanceCreator with Gson for this type may fix this problem..
But this error only presents on older android versions (below 5.0)
I tried implementing default constructor :
constructor: this(PostModel(), true, QuestionModel(), emptyList(), true)
But it gave me java.lang.VerifyError instead
I am using retrofit2 with rxjava2 and gson converter Version 2.3
My kotlin version is 1.1.51
Is it known bug? Or did I do something wrong?
No-arg compiler plugin
The no-arg compiler plugin generates an additional zero-argument constructor for classes with a specific annotation.
The generated constructor is synthetic so it can’t be directly called from Java or Kotlin, but it can be called using reflection.
This allows the Java Persistence API (JPA) to instantiate the data class although it doesn't have the zero-parameter constructor from Kotlin or Java point of view (see the description of kotlin-jpa plugin below).
Using in Gradle
The usage is pretty similar to all-open.
Add the plugin and specify the list of annotations that must lead to generating a no-arg constructor for the annotated classes.
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
apply plugin: "kotlin-noarg"
Source https://kotlinlang.org/docs/reference/compiler-plugins.html

What is legitimate way to get annotations of a pure Kotlin property via reflection, are they always missing?

I'm trying to get annotations from Kotlin data class
package some.meaningless.package.name
import kotlin.reflect.full.memberProperties
annotation class MyAnnotation()
#MyAnnotation
data class TestDto(#MyAnnotation val answer: Int = 42)
fun main(args: Array<String>) {
TestDto::class.memberProperties.forEach { p -> println(p.annotations) }
println(TestDto::class.annotations)
}
I need to process class annotation to make a custom name serialization of GSON however no matter how I declare annotation class it never gets detected
The program always outputs
[]
[#some.meaningless.package.name.MyAnnotation()]
which means only class level annotations are present
Ok,
it seems that the culprit was, that Kotlin annotations have default #Target(AnnotationTarget.CLASS) which is not stressed enough in documentation.
After I added #Target to the annotation class it now works properly
#Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
annotation class MyAnnotation()
Now it prints out
[#some.meaningless.package.name.MyAnnotation()]
[#some.meaningless.package.name.MyAnnotation()]
As a side affect it will force the compiler to check that the annotation is applied as required, in current version of Kotlin, if explicit #Targetis not present only class level annotations are kept but no validity checks performed.
As Kotlin reference said as below:
If you don't specify a use-site target, the target is chosen according to the #Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following: param > property > field.
To make the annotation annotated on a property, you should use site target, for example:
#MyAnnotation
data class TestDto(#property:MyAnnotation val answer: Int = 42)
However, annotations with property target in Kotlin are not visible to Java, so you should double the annotation, for example:
#MyAnnotation // v--- used for property v--- used for params in Java
data class TestDto(#property:MyAnnotation #MyAnnotation val answer: Int = 42)