我正在尝试构建我的第一个注释处理器,并且进展顺利。我正在创建一个代码生成处理器,该处理器基本上为定义的接口生成SharedPreferences
。我当前的注释是SharedPrefs
和Default
。 @SharedPrefs
通知处理器该文件是接口,需要生成的prefs文件。 @Default
是我在界面中注释的一些属性,以便让处理器知道将默认值设置为什么。可以有多个文件定义为@SharedPrefs
。
我目前使用以下代码来获取带有@SharedPrefs
和@Default
注释的文件的列表:
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
...
roundEnv.getElementsAnnotatedWith(Default::class.java)?.forEach {
...
}
}
@SharedPrefs
:
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS)
annotation class SharedPrefs(val showTraces: Boolean = false)
@Default
:
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.PROPERTY)
annotation class Default(val defaultValue: String = "[null]")
使用中:
@SharedPrefs
interface InstanceSettings {
var wifiPassword: String
@Default("20")
var count: Int
}
原样,内部forEach
从带有@Default
注释的all文件中返回all属性。代码生成工作正常,但是这似乎不是最好的方法。有没有办法只获取我正在处理的当前@SharedPrefs
类中的属性?例如,类似:
roundEnv.getElementsAnnotatedWith(SharedPrefs::class.java)?.forEach { element ->
...
element.methodToGetAnnotatedProperties(Default::class.java)?.forEach {
...
}
}
[我发现,对于我注释的方法
@SomeAnnotation
fun someMethod()
我可以遍历element.enclosingElements
,并使用enclosingElement.getAnnotation(<SomeAnnotation::class.java>)
查找其是否具有注释。不幸的是,如果我错了,请纠正我,我无法使用AnnotationTarget.FIELD
注释接口变量,因为它们是接口并且没有实现,因此它们没有后备字段。因此,我正在使用AnnotationTarget.PROPERTY
。当遍历封闭的元素时,所有变量都显示为getter和setter。对于上述InstanceSettings
的示例,我得到getWifiPassword
,setWifiPassword
,getCount
和setCount
。我不仅获得wifiPassword
或count
的元素。由于生成了它们,因此调用getAnnotation(Default::class.java)
将始终返回null。
此外,任何人都知道的有关注释处理的任何其他资源都将成为注释中的重要补充。谢谢!
有人问了Java中的类似问题here
这里是您如何创建将为您工作的扩展功能的方法!
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
}
所以我想我已经找到了解决方法:
以InterfaceSettings
为例:
@SharedPrefs
interface InstanceSettings {
var wifiPassword: String
@Default("20")
var count: Int
}
简化的生成的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() {
}
}
}
调用roundEnv.getElementsAnnotatedWith(Default::class.java)
时返回的元素是count$annotations
。因此,当我呼叫getEnclosingElement()
时,会返回DefaultImpls
。如果我呼叫getEnclosingElement()
再次,则返回InstanceSettings
。我实际上对该结果调用了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
}
}