Kotlin注释:获取接口内部注释属性

问题描述 投票:1回答:2

概述

我正在尝试构建我的第一个注释处理器,并且进展顺利。我正在创建一个代码生成处理器,该处理器基本上为定义的接口生成SharedPreferences。我当前的注释是SharedPrefsDefault@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的示例,我得到getWifiPasswordsetWifiPasswordgetCountsetCount。我仅获得wifiPasswordcount的元素。由于生成了它们,因此调用getAnnotation(Default::class.java)将始终返回null。

此外,任何人都知道的有关注释处理的任何其他资源都将成为注释中的重要补充。谢谢!

android kotlin annotations
2个回答
0
投票

有人问了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
}

0
投票

所以我想我已经找到了解决方法:

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
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.