【问题标题】:How to prevent Eclipse from generating type annotations when assigning expression to local variable将表达式分配给局部变量时如何防止Eclipse生成类型注释
【发布时间】:2020-07-22 14:41:31
【问题描述】:

假设我有这样的 Java 代码:

package test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

public class Test {

    @NotNull
    public static Object object() {
        return new Object();
    }

    public static void test() {
        object();
    }
}

@Target({ ElementType.METHOD, ElementType.TYPE_USE })
@interface NotNull {}

当我在“object();”上使用快速修复 (Ctrl+1) 操作“Assign statement to new local variable”时打电话,我收到了:

public static void test() {
    @NotNull
    Object object = object();
}

我不想在我的客户端 Java 代码中添加注释,因为这对我来说只是噪音。我怎样才能防止它一直被生成,而是得到它?

public static void test() {
    Object object = object();
}

所有这一切只发生在注解有@Target(TYPE_USE)时,并且只有当org.eclipse.jdt.core.compiler.compliance=8或更高版本的.settings/org.eclipse.jdt.core.prefs时发生

为了记录,我还提交了enhancement request 565463

(现实世界的 API 正在声明此类注释以实现更好的 Kotlin 互操作性(使用 JetBrains 注释),因为 Kotlin 可以使用它来区分 TT?,并避免使用 T!

【问题讨论】:

  • 我无法在 Eclipse 2020-06 中使用 org.jetbrains.annotations-1.5.0.jar 以及 “使用内容辅助从中创建局部变量”的不同方式来重现此问题(你是用哪种方式拿?请说出你按了哪些键)。
  • 我不知道那是什么叉子,但我使用的是the official distribution org.jetbrains:annotations:19.0.0。反正@Target的元素类型是一样的,那么让我们看看如何复现吧。
  • @howlger 这似乎与Eclipse 在.settings/org.eclipse.jdt.core.prefs 中默认为org.eclipse.jdt.core.compiler.compliance=1.5 有关,以防尚不支持哪种类型的注释,因此快速修复操作无法以这种方式工作。只要合规性升级到 8 或更高,我就可以在原版项目中再次重现它。作为记录,我在带有 Eclipse 2020-06 的 Windows 上使用 Ctrl+1。抱歉,我应该称之为快速修复,而不是内容辅助
  • 不幸的是,这仍然无法重现,annotations-19.0.0.jar 和 Java 8 或 Java 11 在普通(非 Maven)Java 项目中都无法重现。请在 Eclipse 2020-06 的新工作区中显示一个可用于在新的纯 Java 项目中重现此内容的可编译类(而不是单行代码)。
  • 感谢您报告错误。但在我看来,这似乎是项目的错误配置而不是错误(请参阅下面的答案)。

标签: java eclipse annotations


【解决方案1】:

@NotNull,在您的情况下是不需要的,当且仅当未启用或错误配置基于注释的空值分析时才会添加。

Project > Properies: Java > Compiler部分中Null analysis

  1. 确保选中复选框启用基于注释的空值分析
  2. 不选中复选框Use default annotation for null specification,点击配置...链接并test.NotNull(或org.jetbrains.annotations.NotNull)配置为'NonNull'注释

请注意,只会添加 ElementType.TYPE_USE 注释。对于带有ElementType.TYPE_USE 注释的方法(不能添加到void 方法),注释指的是返回类型,而不是方法本身。换句话说,当调用这样的方法时,您会得到一个带注释的对象。对我来说,为变量的类型添加 Use of a type 注释是预期的行为。

只有在您的情况下,注释才会变成 unclear,例如具有两个目标 ElementType.TYPE_USEElementType.METHOD。注释是指返回类型(因此添加它是有意义的)还是方法是指方法本身(因此不应添加)?

也请不要,与 org.jetbrains.annotations.NotNull 相比,org.eclipse.jdt.annotation.NonNull 没有目标 ElementType.METHOD。方法声明怎么可能是null@NotNull 方法的含义是什么?根据Javadoc of org.jetbrains.annotations.NotNull("... null 值被禁止返回(for methods)..."),目标ElementType.METHOD 似乎在这里被错误地添加了,因为它确实不参考method declaration

【讨论】:

  • 非常感谢您的解释。我认为这对于 Stack Overflow 问题来说已经足够了,因此未来的访问者可以在需要时使用它来应用变通方法。这是否需要可以在错误中进一步讨论:bugs.eclipse.org/bugs/show_bug.cgi?id=565463
【解决方案2】:

虽然问题很笼统,但问题背后的用例是 jOOQ API,它开始在 jOOQ 3.14 中添加 Jetbrains 注释(请参阅#6244)以实现更好的 Kotlin 互操作性,例如

interface ResultQuery<R> {
  @NotNull Result<R> fetch();
  @Nullable R fetchOne();
}

在 jOOQ 的情况下,对注解的依赖可以在 Maven 中设置为可选/提供,或者在 JPMS 中设置为 static,这样普通的 Java 客户端代码默认看不到注解:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <scope>provided</scope>
    <optional>true</optional>
</dependency>

Kotlin 编译器仍然可以看到它:

val q: ResultQuery<R> = ...
q.fetch() // Result<R!>
q.fetchOne() // R?

如果您无法控制的第三方引入了依赖项,则可以像这样将其排除:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    
    <exclusions>
        <exclusion>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
        </exclusion>
    </exclusions>
</dependency>

【讨论】:

  • 一个可选的 Maven 依赖项会阻止 org.jetbrains 注释被包含在胖 JAR 中,但由于它们是 RetentionPolicy.CLASS 而不是 RetentionPolicy.SOURCE,所以对它们的引用仍然在字节码中,对吧? Kotlin 编译器是否无法像 Eclipse 一样从源代码中读取空注释,并且 Kotlin 编译器是否只需要 org.jetbrains 空注释?此外,这与您的问题有什么关系?
  • @howlger:当然,需要包含字节码。第三方库中可能不提供源代码。我最初的问题比当前的问题更具体。我只是想帮助任何可能遇到此问题并且可能会发现此解决方法有用的未来访问者。
  • Eclipse 还可以从 Javadoc 中读取 null 分析注释,因此无需污染字节码。我不清楚这对于使 Maven 依赖项可选的 Java 编辑器意味着什么。我也没有明白,为什么你不想将空注释配置为空注释(不配置它们,你将无法从中受益)。
  • @howlger:如果您知道一个更好的解决方案,可以帮助 Kotlin 编译器在使用 Java API 时推断可空性,我会全力以赴。
  • 我不知道 Kotlin 编译器是否能够从源代码或 Javadoc (external annotations don't seem to work either) 中获取空注释。与此无关,在 Eclipse 中,空注释应配置为空注释,以便隐式处理这些 TYPE_USE 注释(无需在使用它们的代码中显式存在)。
猜你喜欢
  • 2021-04-01
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 2015-03-23
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
相关资源
最近更新 更多