简体   繁体   English

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

[英]Kotlin Annotation: Get interface inner annotated properties

Overview概述

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 .我当前的注释是SharedPrefsDefault @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

Implementation执行

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
}

Problem问题

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 {
    ...
  }
}

* EDIT * * 编辑 *

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示例,我得到了getWifiPasswordsetWifiPasswordgetCountsetCount I do not get an element for just wifiPassword or count .没有得到wifiPasswordcount的元素。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM