我有这个示例设置:

100

package p;

public enum E { E }

100

package p;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface A {
    p.E e();
}

100

package q;

import p.*;

@A(e = E.E)
public class Test {
    public static void main(String[] args) {
        System.out.println("Test.main()");
    }
}

所以,我现在可以这样做:

$ javac q/Test.java
$ rm p/*.class
$ ll */*
-rw-r--r-- 1 lukas 197609 118 Mar 28 10:21 p/A.java
-rw-r--r-- 1 lukas 197609  32 Mar 28 09:43 p/E.java
-rw-r--r-- 1 lukas 197609 486 Mar 28 10:22 q/Test.class
-rw-r--r-- 1 lukas 197609 153 Mar 28 09:55 q/Test.java
$ java q/Test
Test.main()

没问题,注释是可选的,并被运行时忽略,不是NoClassDefFoundError

但是,当我同时删除p的源文件时,保留编译后的Test.class:

$ rm -Rf p

然后创建:

100

package x;

public class Test2 {
    q.Test test;
}

编译该类会给出一个警告:

$ javac x/Test2.java
warning: unknown enum constant E.E
  reason: class file for p.E not found
1 warning

替代方案,不会产生这样的警告

没有枚举

对于不依赖于任何枚举的批注,我没有收到此警告.即对这些重复该过程,则不会出现任何警告:

100

package p;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface A {}

100

package q;

import p.*;

@A
public class Test {
    public static void main(String[] args) {
        System.out.println("Test.main()");
    }
}

类引用

A引用Class<E>而不是E.E枚举值时,我仍然没有收到任何警告:

100

package p;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface A {
    Class<?> a();
}

100

package q;

import p.*;

@A(a = E.class)
public class Test {
    public static void main(String[] args) {
        System.out.println("Test.main()");
    }
}

我的问题:

  1. 根据JLS的说法,这是一个正确的警告吗?在我看来,这似乎是javac中的一个错误,因为注释是可选的,如果不涉及enum类型,则不会产生警告,但我可能遗漏了一些东西.
  2. 有什么方法可以在客户端代码中解决此警告吗?

For context: the real world use-case is:

  • 包含注释的p个包来自JAXB
  • 包含引用注释的库代码的q包是一个对p的依赖是可选的库.(具体来说,jOOQ为more details here)
  • x包是客户端代码,这取决于q包,它对p有一个可选的依赖项,这意味着在默认情况下,该依赖项实际上是缺失的.

推荐答案

同样在JDK-6550655/how-to-avoid-javac-warning-unknown-enum-constant-reason-class-file-not-found?noredirect=1#comment133841351_75864JDK-6550655">commented by user yyyy和JDK-655065583" rel="nofollow noreferrer">library bug tracker上,当前行为是由修复程序JDK-6550655定义的,该修复程序在Java 7中引入了警告(在此之前,这种注释/枚举的使用会导致编译错误).

JDK-6550655略有不同.该警告是在只缺少枚举p.E而不是注释p.A的情况下引入的,在这种情况下,当使用反射API访问p.A时,确实会出现不希望看到的运行时错误.警告开发人员注意这种情况当然是可取的.然而,在本例中,p包的所有内容都不存在,这意味着不可能有任何运行时错误,并且根据注释的设计,不存在应该很好,允许不存在.

在我看来,这是javac中的一个错误,我已经报告了:JDK-8305250.它可能被接受,也可能不被接受或修复.

Java相关问答推荐

获取拦截器内部的IP地址

表格栏上的事件过滤器在PFA中不起作用

那么比较似乎不是词典学的,尽管doctor 这么说

我可以在regex中的字符类中放置断言吗?

Java应用程序崩溃时试图读取联系人从电话

使用标记时,场景大纲不在多个线程上运行

CAMEL 4中的SAXParseException

无法处理批处理侦听器中的反序列化异常

try 创建一个对象,使用它,然后使用一条语句将其存储为列表

是否在允许数组元素为空时阻止 idea 为空性警告?

PDFBox未加载内容

使用用户引入的参数生成人员数组

使用Jackson库反序列化json

对从Spring Boot 3.1.5升级到3.2.0的方法的查询验证失败

在使用具有不同成本的谓词调用allMatch之前对Java流进行排序会带来什么好处吗?

具有多个模式的DateTimeForMatter的LocalDate.parse失败

使用迭代器遍历HashMap不会因IF条件而停止

如何对存储为字符串的大数字数组进行排序?

rest api服务 spring 启动中出现IllegalFormatConversionException

Java返回生成器的实现