[英]Kotlin Annotation: Get interface inner annotated properties
I'm trying to build my first annotation processor and it's going pretty well.我正在尝试构建我的第一个注释处理器,并且进展顺利。 I am creating a code generating processor that basically generates
SharedPreferences
for a defined interface.我正在创建一个代码生成处理器,它基本上为定义的接口生成
SharedPreferences
。 My current annotations are SharedPrefs
and Default
.我当前的注释是
SharedPrefs
和Default
。 @SharedPrefs
informs the processor that the file is an interface and needs a generated prefs file. @SharedPrefs
通知处理器该文件是一个接口,需要一个生成的 prefs 文件。 @Default
is what I annotated some properties in the interface as in order to let the processor know what to set the default value to. @Default
是我在界面中注释了一些属性,以便让处理器知道将默认值设置为什么。 There can be multiple files defined as @SharedPrefs
.可以有多个文件定义为
@SharedPrefs
。
I currently use the following code to get a list of files annotated with @SharedPrefs
and the @Default
s:我目前使用以下代码来获取用
@SharedPrefs
和@Default
s注释的文件列表:
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
...
roundEnv.getElementsAnnotatedWith(Default::class.java)?.forEach {
...
}
}
@SharedPrefs
: @SharedPrefs
:
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS)
annotation class SharedPrefs(val showTraces: Boolean = false)
@Default
: @Default
:
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.PROPERTY)
annotation class Default(val defaultValue: String = "[null]")
In Use:正在使用:
@SharedPrefs
interface InstanceSettings {
var wifiPassword: String
@Default("20")
var count: Int
}
As is, the inner forEach
is returning all properties from all files annotated with @Default
.由于是内部
forEach
将返回从带注释的所有文件的所有属性@Default
。 The code generation works fine, but this doesn't seem like the best way forward.代码生成工作正常,但这似乎不是最好的前进方式。 Is there a way to get just the properties w/in the current
@SharedPrefs
class that I'm processing?有没有办法只获取我正在处理的当前
@SharedPrefs
类中的属性? For instance, something like:例如,类似于:
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
...
element.methodToGetAnnotatedProperties(Default::class.java)?.forEach {
...
}
}
I found that, for methods that I annotate我发现,对于我注释的方法
@SomeAnnotation
fun someMethod()
I can loop through the element.enclosingElements
and find if it has an annotation using enclosingElement.getAnnotation(<SomeAnnotation::class.java>)
.我可以遍历
element.enclosingElements
并使用enclosingElement.getAnnotation(<SomeAnnotation::class.java>)
查找它是否有注释。 Unfortunately, and correct me if I'm wrong here, I can't annotate interface variables with an annotation with AnnotationTarget.FIELD
since they don't have a backing field since it's an interface and they're not implemented.不幸的是,如果我在这里错了,请纠正我,我不能用
AnnotationTarget.FIELD
来注释接口变量,因为它们没有支持字段,因为它是一个接口并且它们没有实现。 Therefore, I'm using AnnotationTarget.PROPERTY
.因此,我使用
AnnotationTarget.PROPERTY
。 When looping through the enclosing elements, all of the variables show up as getters and setters.当循环遍历封闭元素时,所有变量都显示为 getter 和 setter。 For the example above for
InstanceSettings
, I get getWifiPassword
, setWifiPassword
, getCount
and setCount
.对于上面的
InstanceSettings
示例,我得到了getWifiPassword
、 setWifiPassword
、 getCount
和setCount
。 I do not get an element for just wifiPassword
or count
.我没有得到
wifiPassword
或count
的元素。 Calling getAnnotation(Default::class.java)
will always return null on these since they are generated.调用
getAnnotation(Default::class.java)
将始终在这些上返回 null,因为它们是生成的。
Also, any other resources on annotation processing that anyone knows of would be a great addition in the comments.此外,任何人都知道的有关注释处理的任何其他资源都将是评论中的一个很好的补充。 Thanks!
谢谢!
Similar question in java was asked here java中的类似问题在这里被问到
Here is how you can create an extension function which will do job for you!这是您如何创建一个可以为您工作的扩展功能!
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
...
roundEnv.findNestedElements(SharedPrefs::class, Default::class)?.forEach {
...
}
}
fun <T> RoundEnvironment.findNestedElements(parent: KClass<*>, child: KClass<T>): List<Element>? {
val childs = this.getElementsAnnotatedWith(child.java)
val list = ArrayList<Element>()
for (element in childs)
{
if (element.getEnclosingElement().getAnnotation(parent.java) != null)
{
list.add(element)
}
}
return if(list.isEmpty()) null else list
}
So I think I've found the solution:所以我想我已经找到了解决方案:
For the example of InterfaceSettings
:对于
InterfaceSettings
的示例:
@SharedPrefs
interface InstanceSettings {
var wifiPassword: String
@Default("20")
var count: Int
}
The simplified generated Java code is :简化生成的Java代码是:
public interface InstanceSettings {
@NotNull
String getWifiPassword();
void setWifiPassword(@NotNull String var1);
int getCount();
void setCount(int var1);
public static final class DefaultImpls {
public static void count$annotations() {
}
}
}
The element returned when calling roundEnv.getElementsAnnotatedWith(Default::class.java)
is count$annotations
.调用
roundEnv.getElementsAnnotatedWith(Default::class.java)
时返回的元素是count$annotations
。 So when I call getEnclosingElement()
, DefaultImpls
is returned.因此,当我调用
getEnclosingElement()
,将返回DefaultImpls
。 If I call getEnclosingElement()
again , InstanceSettings
is returned.如果我再次调用
getEnclosingElement()
,则返回InstanceSettings
。 I actually call getSimpleName()
on that result and compare it with the className from the item annotated with @SharedPrefs
to see if it is a child:我实际上对该结果调用了
getSimpleName()
并将其与使用@SharedPrefs
注释的项目中的 className 进行比较,以查看它是否是子项:
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
val className = element.simpleName.toString()
val defaults = roundEnv.getElementsAnnotatedWith(Default::class.java)?.filter {
// it.enclosingElement -> DefaultImpls
// DefaultImpls.enclosingElement -> com.mypackage.InstanceSettings
it.enclosingElement.enclosingElement.simpleName == className
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.