I’m writing a library in Kotlin targeting the JVM, which means I need 100% usability in Java. I plan to use the kotlin-reflect library, but found some unexpected result when writing test cases against these reflection operations in Java.
Edit: I use the Kotlin version 1.0.0-beta-4589.
I have an annotation written in Java:
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Marker {
}
And a Java bean:
public class JavaPerson {
private String name;
@Marker
private String email;
@Marker
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Also I have an equivalent version in Kotlin:
class KotlinPerson(@get:org.swordess.toy.kotlin.misc.reflection.Marker var name: String?, @field:Marker var email: String?)
I try to dig out what behavior Kotlin exactly make via:
fun printProperties(c: KClass<*>) {
println("${c.qualifiedName} >>>")
c.memberProperties.forEach {
println("property(name=${it.name}, annotations=${it.annotations})")
println("\tkotlinGetter: ${it.getter}, annotations=${it.getter.annotations}")
it.javaGetter?.let { println("\tjavaGetter: $it, annotations=${it.annotations}") }
if (it is KMutableProperty<*>) {
println("\tkotlinSetter=${it.setter}, annotations=${it.setter.annotations}")
it.javaSetter?.let { println("\tjavaSetter=$it, annotations=${it.annotations}") }
}
}
}
And the output when applying printProperties to my two versions of beans:
org.swordess.toy.kotlin.misc.reflection.KotlinPerson >>>
property(name=email, annotations=[])
kotlinGetter: kotlin.reflect.jvm.internal.KProperty1Impl$Getter@71809907, annotations=[]
javaGetter: public final java.lang.String org.swordess.toy.kotlin.misc.reflection.KotlinPerson.getEmail(), annotations=[Ljava.lang.annotation.Annotation;@6b927fb
kotlinSetter=kotlin.reflect.jvm.internal.KMutableProperty1Impl$Setter@5876a9af, annotations=[]
javaSetter=public final void org.swordess.toy.kotlin.misc.reflection.KotlinPerson.setEmail(java.lang.String), annotations=[Ljava.lang.annotation.Annotation;@6b927fb
property(name=name, annotations=[])
kotlinGetter: kotlin.reflect.jvm.internal.KProperty1Impl$Getter@6572421, annotations=[]
javaGetter: public final java.lang.String org.swordess.toy.kotlin.misc.reflection.KotlinPerson.getName(), annotations=[Ljava.lang.annotation.Annotation;@6b81ce95
kotlinSetter=kotlin.reflect.jvm.internal.KMutableProperty1Impl$Setter@2a798d51, annotations=[]
javaSetter=public final void org.swordess.toy.kotlin.misc.reflection.KotlinPerson.setName(java.lang.String), annotations=[Ljava.lang.annotation.Annotation;@6b927fb
org.swordess.toy.kotlin.misc.reflection.JavaPerson >>>
property(name=email, annotations=[])
kotlinGetter: kotlin.reflect.jvm.internal.KProperty1Impl$Getter@65d09a04, annotations=[]
kotlinSetter=kotlin.reflect.jvm.internal.KMutableProperty1Impl$Setter@6a2f6f80, annotations=[]
property(name=name, annotations=[])
kotlinGetter: kotlin.reflect.jvm.internal.KProperty1Impl$Getter@5b94b04d, annotations=[]
kotlinSetter=kotlin.reflect.jvm.internal.KMutableProperty1Impl$Setter@8c3b9d, annotations=[]
From the output, I found:
- Though I declare use-site target
Marker
annotated toKotlinPerson
’susername
andemail
property, annotation are both visible by javaGetter and javaSetter, is this expected? - It’s not possible to fetch annotations from
JavaPersion
, is this expected? If yes, I have no way to saykprop.javaGetter.isAnnotationPresent(Marker::class.java)
, which further means NOT POSSIBLE to use my Kotlin library (which relies on kotlin-reflect) in Java! It’s very frustrated!
And this question come to me when I use Kotlin, also related to Annotation and reflection:
- Kotlin has a type
KAnnotatedElement
which has a propertypublic val annotations: List<Annotation>
, but I have no way to declare a (maybe) Annotation Type, thus I cannot say, for exampleMarker::class.anno in kElem.annotations
. From the source code of the mentionedAnnotation
:
package kotlin
public interface Annotation {
}
Nothing is there. Or, I can treat the Kotlin’s Annotation
type like a general type, so I could say kElem.annotations.firstOrNull { it is Marker }
?
In a word, what is this KAnnotatedElement.annotations
property designed for?