【问题标题】:How can I use a Java Annotation in Scala?如何在 Scala 中使用 Java 注解?
【发布时间】:2020-04-07 16:21:57
【问题描述】:

我有一个自定义 Java 注释,它会在编译测试源时生成一个文件。但是当我将此注解导入 Scala 类并以与在 Java 中相同的方式使用它时,Scala 不会处理它。

Java 注释

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Trace {
    public String key() default "";
    public byte step() default 0;
    public String url() default "";
}

@SupportedAnnotationTypes("com.custom.annotations.Trace")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@AutoService(Processor.class)
public class TraceProcessor extends AbstractProcessor {

    public static final String DEFAULT_FILE_PATH = "target/";
    public static final String DEFAULT_FILE_NAME = "trazability.txt";

    private Messager messager;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> annotatedElements = getTraceAnnotatedElements(roundEnv);
        if(annotatedElements.size() == 0) {
            return true; // If there is not annotation, fast exist.
        }

        System.out.println("Processing @Trace annotations...");
        try {
            generateTraceFile(annotatedElements);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        // get messager for printing errors
        messager = processingEnvironment.getMessager();
    }

    private Set<? extends Element> getTraceAnnotatedElements(RoundEnvironment roundEnv) {
        return roundEnv.getElementsAnnotatedWith(Trace.class);
    }

    private void generateTraceFile(Set<? extends Element> annotatedElements) throws FileNotFoundException {
        PrintWriter out = new PrintWriter(DEFAULT_FILE_PATH + DEFAULT_FILE_NAME);

        System.out.println("Annotated elements with @Trace: " + annotatedElements.size());
        for (Element element : annotatedElements) {
            if (element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.METHOD) {
                String key = element.getAnnotation(Trace.class).key();
                int step = element.getAnnotation(Trace.class).step();

                if(element.getKind() == ElementKind.METHOD) {
                    String className = ((TypeElement) element.getEnclosingElement()).getQualifiedName().toString();
                    String methodName = element.getSimpleName().toString();
                    System.out.println("Add " + element.getKind().name() + " with key: " + key + " step: " + step + " class: " + className + " method: " + methodName);
                    out.print(key + ";" + step + ";" + className + "." + methodName);
                } else {
                    String packageName = ((Symbol) element).getQualifiedName().toString();
                    String className = packageName + "." + element.getSimpleName().toString();
                    System.out.println("Add " + element.getKind().name() + " with key: " + key + " step: " + step + " class: " + className);
                    out.print(key + ";" + step + ";" +  className);
                }
                out.println();
            }
        }
        out.println();
        out.close();
        System.out.println("File trazability generated into target folder");
    }

    private void printError(Element element, String message) {
        messager.printMessage(Diagnostic.Kind.ERROR, message, element);
    }

}

斯卡拉

import com.custom.annotations.Trace

@Trace(key = "ECI-12")
class Simulation1 extends Simulation {}

当我在 Java 源代码中使用 java 注释时,Trace 注释由 TraceProcessor 处理并生成一个文件。但是当我对 Scala 做同样的事情时,它就不起作用了。

【问题讨论】:

标签: java scala maven


【解决方案1】:

在 scala 代码中使用 java 注释会导致不可预知的结果,其中大多数根本不起作用。请不要在您的 Scala 代码中使用它们,因为这样做会招致 Java 和 Scala 人的仇恨。将你最喜欢的 java 世界中的库与 scala 融合在一起并不能让你从 scala 中获得最好的结果,但会引发一堆在不同资源上很少考虑的问题。 Scala有自己的生态系统,即使你对java非常精通,只要你能解决scala库的问题,最好避免使用java库。

Java 注释通常用于去除由 java 冗长语法和糟糕的类型系统强制执行的样板文件。 Scala 有自己的元编程框架(黑盒宏、白盒宏、宏注释和隐式宏)和许多其他抽象的东西,例如具有 HKT 的强大类型系统和无所不能的隐式搜索机制。因此,在大多数情况下,您绝对不需要宏注释。

此外,您的问题可能存在 scala 解决方案。如果您决定描述问题而不是带来一堵代码墙,那么有人可以为您找到它。

【讨论】:

  • 目标是使用@Trace 注释来注释几个测试类,并生成一个文件,其中包含具有此注释的合格类名称列表。
  • @Franb,您可以创建空注释并使用scalameta.org grep 标记有它的所有类。
【解决方案2】:

Java 注释仅适用于 Java 编译器,因为处理器需要使用 Java AST。您必须为 Scala 编写自己的宏注解,它使用的编译器与 Java 的注解处理器不兼容。见这里:https://docs.scala-lang.org/overviews/macros/annotations.html

【讨论】:

  • 我正在使用 scala 2.12.10,我读到宏是一个实验性功能:docs.scala-lang.org/overviews/macros/overview.html。我想要class Trace(val key: String) extends ClassfileAnnotation 之类的东西,但我应该如何与“处理器”或等效的scala 链接。我的意思是,如何编写注释处理器以便在编译时运行它?
  • 对不起,我帮不了你。我不太了解具体细节。不过,您可能应该阅读更多文档。但是,您提供的链接是针对 def 宏的,这在这里可能无济于事。你需要宏注解,它可以应用于类。
  • 要进行注释,您可以扩展 StaticAnnotation。然后你把对宏实现的引用放在注解中(我认为与Java不同,处理器与注解是分开的)。然后实际的宏实现需要一个上下文和一些 AST 节点,并可以从中生成东西。看这篇文章的例子:medium.com/kifi-engineering/…
猜你喜欢
  • 2019-12-26
  • 2014-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
相关资源
最近更新 更多