Kotlin 注解的使用目标(Use-site Target)问题

Kotlin 注解的使用目标(Use-site Target)问题

在测试kotlin的注解的时候发现了些许问题

这里我假设了一个小需求 ,有一个User实体

dataclassUser(valage:Number,varname:String,vargender:String="")

再自定义一个注解

@Target(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY)

@Retention(AnnotationRetention.RUNTIME)

annotationclassGender(

valvalue:String

)

目的是在实例化User的时候给User加一个Gender的注解,再通过反射把value值赋给user对象

于是开始代码

classAnnotationTest{

@Gender(value="男")

valuser2=User(20,"张三")


  @Test

funtestAnnotation() {

valuser=AnnotationTest::user2

valobj=user.get(this)

valgender=User::gender

valannotation=user.findAnnotation<Gender>()

  gender.set(obj,annotation2?.value?:"")

println(user2)

   }

}

运行后打印

User(age=20,name=张三,gender=男)

看起来没什么毛病

于是我又想使用java的反射方式尝试一下

@Test

funbuildUser() {

valfield=this@AnnotationTest::class.java.getDeclaredField("user2");

valannotations=field.declaredAnnotations

valobj=field.get(this)

for(annotationinannotations) {

if(annotationisGender) {

valvalue=annotation.value

println("注解value : $value")

valgenderField=obj::class.java.getDeclaredField("gender")

genderField.isAccessible=true

genderField.set(obj,value)

       }

   }

println(user2.toString())

}

查看一下打印结果

User(age=20,name=张三,gender=)

咦 ,什么情况 kotlin 注解不是号称兼容java注解的么,于是查找了下资料 .

发现kotlin的注解在使用的时候是需要指定(Use-site Target)的

file 包含在文件中声明的顶层函数和顶层属性注解, 比如`@file:JvmName("ClassName");

property (使用这个目标的注解, 在 Java 中无法访问);

field 相当于java的field;

get (属性的 get 方法);

set (属性的 set 方法);

receiver (扩展函数或扩展属性的接受者参数);

param (构造器的参数);

setparam (属性 set 方法的参数);

delegate (保存代理属性的代理对象实例的域变量);

并查到kotlin的注解如果不指定注解的使用目标(Use-site Target), 那么将会根据这个注解的 @Target 注解来自动选定使用目标. 如果存在多个可用的目标, 将会使用以下列表中的第一个(优先级由上至下):

param;

property;

field.

Bingo!! 问题出来了 我这里定义的Gender注解@target指定的是(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY),

由于其中包含AnnotationTarget.PROPERTY,并且在使用@Gender的时候并没有指定注解目标(Use-site Target)

导致注解目标默认成property ,而property注解信息并不能在java的反射中获取到

于是解决方案就来了

第一种方案

去掉定义的Gender注解@target中的AnnotationTarget.PROPERTY.由于定义的时候排除掉了property 在使用的时候自然不需要再指定

@Target(AnnotationTarget.FIELD)

@Retention(AnnotationRetention.RUNTIME)

annotationclassGender(

valvalue:String

)

使用时(由于未使用kotlin的property属性 在获取注解的时候自然不能再通过 findAnnotation 获取到 ,这里需要使用javaField 获取)

classAnnotationTest{

@Gender(value="男")

valuser2=User(20,"张三")


  @Test

funtestAnnotation2() {

valuser=AnnotationTest::user2

valobj=user.get(this)

valgender=User::gender

valannotation=user.javaField?.getAnnotationsByType(Gender::class.java)

if(annotation?.isNotEmpty()==true) {

gender.set(obj,annotation[0].value?:"")

       }

println(user2)

   }

}

打印结果User(age=20,name=张三,gender=男)

第二种方案 使用注解时指定注解目标(Use-site Target),通过@目标:注解的语法

@Target(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY)

@Retention(AnnotationRetention.RUNTIME)

annotationclassGender(

valvalue:String

)

使用时( 加上@field:Gender 表示只在 field上使用注解,  当然也可以使用kotlin的特性@property:Gender ,只不过这种方式并不兼容java)

classAnnotationTest{

@field:Gender(value="男")

valuser2=User(20,"张三")


  @Test

funtestAnnotation2() {

valuser=AnnotationTest::user2

valobj=user.get(this)

valgender=User::gender

valannotation=user.javaField?.getAnnotationsByType(Gender::class.java)

if(annotation?.isNotEmpty()==true) {

gender.set(obj,annotation[0].value?:"")

       }

println(user2)

   }

}

打印结果 User(age=20, name=张三, gender=男)

总结:

由于kotlin的属性(property)包含java中的field及setter和getter,在使用注解的时候会产生歧义,所以kotlin创造了注解目标(Use-site Target)以明确注解的作用目标,所以在不明确注解的@target的时候使用注解时尽量指明注解的使用目标(Use-site Target),否则可能会出现未知的问题

使用kotlin注解时如果未指定使用目标(Use-site Target),其默认的使用目标是根据注解的@target来决定的(这里是重点),而并不是固定的.其优先级顺序为 param ->  property ->  field

kotlin注解的@property:并不能在java中获取到 这是kotlin的特性,具体获取注解的方式如下

println(Example::foo.annotations)// 获取 @property: 修饰的注解

println(Example::foo.findAnnotation<Ann>())// 获取 @property: 修饰的注解

println(Example::foo.getter.annotations)// 获取 @get: 修饰的注解

println(Example::foo.getter.findAnnotation<Ann>())// 获取 @get: 修饰的注解

println(Example::foo.javaField?.annotations)// java方式获取注解信息,获取 @field: 修饰的注解以及原生java注解

println(Example::foo.javaField?.getAnnotation(Ann::class.java))// java方式获取注解信息,获取 @field: 修饰的注解以及原生java注解

在测试这个问题的时候遇到了一个无比巨坑,ide使用的是AndroidStudio,在调试代码的时候出现了各种各样奇葩的情况,比如@target只有AnnotationTarget.FIELD的情况下却获取不到java的注解信息 ,但能获取到kotlin的注解信息.再或者@target为两个,但未指定注解目标

却获取到了java的注解信息而获取不到kotlin的注解信息.种种如此很是奇葩,后经过调试和分析反编译成java的代码后发现,是由于编译缓存的原因,需要在修改之后 clean一下  或者随便修改一下代码 哪怕是加个注释 让编译器重新编译 问题解决

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容