我们有一个Java项目。我们为-Xlint
启用-Werror
(启用警告)和javac
(将警告视为错误)标记,以确保我们的代码无警告。最近我们决定弃用一堂课。问题是在某些情况下@SuppressWarnings("deprecation")
根本不会抑制弃用警告,从而导致构建失败。以下是我遇到的用例列表:
输入参数。例如
@SuppressWarnings("deprecation")
public class Foo extends Bar<DeprecatedClass>
{ ... }
然而,即使没有压制,这个也没有警告:
@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass>
{ ... }
AFAIK,没有注释导入的语法,因此对于案例1和2,我们的解决方案是导入*或避免导入。对于案例3和案例4,Java 6和7都不会禁止警告。 Java 8将正确地抑制它(可能修复了一个错误)。到目前为止还没有解决方案。
不幸的是,我们此时必须支持Java 6,7和8。有办法解决这个问题吗?它是我们Java API发展的障碍。
附录
很多人问为什么我们仍然在自己的代码库中使用已弃用的类。原因是该项目是一个图书馆,支持许多不同的客户。在引入新的替换API时,我们必须首先弃用旧的API,将其保留在我们的代码库中,等待所有客户端迁移然后将其删除。有三种常见用例:
Foo
和Bar
,其中Foo
扩展了Bar
。我的问题就是案例2和3。Foo
和Bar
,其中Foo
扩展了Collection<Bar>
。情况就是2和4。Foo
和Bar
的所有测试代码。测试代码导入这些类。情况就是这样。为什么要坚持考试?不要忘记,如果发现严重错误(例如内存泄漏,安全问题),并且客户端无法轻松迁移到新版本,我们仍需要为旧API提供错误修复。并且必须测试所有更改。
我觉得我们的情况应该在软件库开发和API演变中相当普遍。令人惊讶的是,Java用了很长时间(直到Java 8)修复了这个bug。
答案 0 :(得分:10)
我很遗憾地说我没有解决你所遇到的问题,但正如你所观察到的那样,已经取得了一些进展。我们一直试图摆脱JDK本身的所有Java编译警告,这是一个漫长而艰难的过程。在2011年的JDK 8开发期间,我帮助kick off the warnings cleanup effort和我之后co-presented a JavaOne talk(slides and audio)了解了这一主题。
最近,我的同事Joe Darcy继续进行警告清理工作,并且已经完成了不同的警告类别并且已经finally reached deprecation warnings。正如您所指出的,编译器在处理抑制弃用警告方面存在一些错误,例如在JDK 8中修复的JDK-6480588。遗憾的是,在JDK 8中仍然无法抑制对已弃用的导入的警告项目。这个错误JDK-8032211最近在我们的JDK 9开发线中得到了修复。事实上,我们仍然在调整@Deprecated
注释的处理。例如,错误JDK-6481080阐明了在@Deprecated
文件中尝试使用package-info.java
实际上并未弃用该包;上个星期刚修复了这个bug。并且有more work to be done,但此时它有些推测。
JDK面临着与您类似的问题,因为我们必须为仍在使用它们的客户端维护已弃用的API。但是,由于我们在内部使用和实现了这些API,因此我们有许多弃用警告可以抑制。在撰写本文时,在我们的JDK 9开发线中,我们仍然无法在没有弃用警告的情况下编译系统。因此,lint警告的javac
选项仍然是:
-Xlint:all,-deprecation
您可能还必须在编译中禁用弃用警告,特别是如果您仍在构建JDK 6.此时我还没有看到解决方法。
关于您的一个弃用案例的最后一点说明:
@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass> { ... }
这不会发出弃用警告,也不会发出。 Java Language Specification, section 9.6.4.6指定如果使用已弃用的实体位于本身已弃用的实体内,则不会发出弃用警告。
答案 1 :(得分:1)
考虑使用-Xmaxwarns,您可以在停止之前控制多少警告。
或者尝试收集警告的数量并使集成过程失败,而不是编译。
例如:https://issues.apache.org/jira/browse/HADOOP-11252。 每个提交给hadoop项目的代码都需要传递自动CI,并且为了增加警告次数而给出-1。
答案 2 :(得分:-3)
通常,当您弃用类时,您不希望任何人在更高版本中使用它。此外,您的代码库也应该停止使用已弃用的类。当你说每个人都不使用MySuperDeprecatedUtil类但继续在你的代码库中使用它时,它看起来很奇怪。
如果你需要在其他一些类中使用你的MySuperDeprecatedUtil类 - 你应该将你用它的类标记为@Deprecated - 每个使用过旧代码的类都应该被弃用,或者会产生编译警告,或者应该被删除,或者应该停止使用已弃用的代码。
如果你不能停止使用你的课程 - 也许现在推荐它还为时过早?
在我的练习中,当我想弃用某个类时,我会创建替换类,例如MySuperFreshUtil。使用MySuperDeprecatedUtil切换所有classess到MySuperFresh util尽可能保留接口(如果不可能 - 使用FQCN和mark方法弃用)。将MySuperDeprecatedUtil标记为@Deprecated并添加注释哪个类以及如何使用它。然后我在单个更改列表中提交此更改。