我们有一个Java项目。我们为-Xlint
启用-Werror
(启用警告)和javac
(将处理警告作为错误)标志,以确保我们的代码没有警告。最近,我们决定弃用一门类(class)。问题是在某些情况下@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演进的障碍。
ADDENDUM
许多人问为什么我们仍然在自己的代码库中使用不推荐使用的类。原因是该项目是一个图书馆,支持许多不同的客户。在引入新的替代API时,我们必须首先弃用旧的API,将其保留在我们的代码库中,等待所有客户端迁移然后将其删除。共有三种常见的用例:
Foo
和Bar
类,其中Foo
扩展了Bar
。我的问题就是这种情况2和3。 Foo
和Bar
类,其中Foo
扩展了Collection<Bar>
。这是情况2和4。Foo
和Bar
类的所有测试代码。测试代码将导入这些类。就是这种情况1. 为什么要继续测试?不要忘记,如果发现了严重的错误(例如内存泄漏,安全问题),并且客户端无法轻松迁移到新版本,我们仍然需要为旧API提供错误修复。并且所有更改都必须经过测试。
我觉得我们的情况在软件库开发和API演变中应该相当普遍。出人意料的是,Java花了这么长时间(直到Java 8)才修复了该错误。
最佳答案
很遗憾地说,对于您所面临的问题,我没有解决方案,尽管您已经观察到了一些进展。我们一直在尝试摆脱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
实际上并没有弃用该软件包。该错误已于上周修复。并且有more work to be done,但在这一点上有些投机。
JDK面临着与您类似的问题,因为我们必须为仍在使用它们的客户端维护不推荐使用的API。但是,由于我们在内部使用和实现此类API,所以我们要抑制很多弃用警告。在撰写本文时,在我们的JDK 9开发线中,如果没有弃用警告,我们仍然无法编译系统。结果,棉绒警告的javac
选项仍然是:
-Xlint:all,-deprecation
您可能还必须在编译中禁用弃用警告,尤其是如果您仍在构建JDK 6时。我目前还没有解决的方法。
关于一种弃用情况的最后说明:
@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass> { ... }
这不会发出弃用警告,也不应该发出。 Java Language Specification, section 9.6.4.6指定如果使用不赞成使用的实体在本身不赞成使用的实体内,则不发出不赞成使用警告。