We have a Java project. We enable -Xlint
(enable warnings) and -Werror
(treat warning as error) flags for javac
, to make sure our code is warning-free. Recently we decide to deprecate a class. The problem is in some cases @SuppressWarnings("deprecation")
will not suppress the deprecation warning at all, resulting in build failure. Below is a list of use cases that I ran into:
Type parameter. For example
@SuppressWarnings("deprecation")
public class Foo extends Bar<DeprecatedClass>
{ ... }
However, this one has no warning even without suppress:
@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass>
{ ... }
AFAIK, there is no syntax for annotating imports, so for case 1 and 2 our solution is to either import * or avoid importing. For case 3 and 4, both Java 6 and 7 do not suppress the warning. Java 8 will correctly suppress it (maybe a bug is fixed). So far no solution for this.
Unfortunately, we have to support Java 6, 7 and 8 at this point. Is there way to deal with the problem? It is a road block for our Java API evolution.
ADDENDUM
Many people ask why do we still use the deprecated class in our own codebase. The reason is that the project is a library, supporting many different clients. When introducing new replacement API, we have to first deprecate our old API, keep it in our codebase, wait for all clients to migrate then remove it. There are three common use cases:
Foo
and Bar
, where Foo
extends Bar
. This is the case 2 and 3 in my question.Foo
and Bar
, where Foo
extends Collection<Bar>
. This is the case 2 and 4.Foo
and Bar
. The test code imports these classes. This is the case 1.Why keep the test? Don't forget that if a serious bug (e.g. memory leak, security issue) is discovered, and the clients can't easily migrate to the new version, we still need to provide bug fix to the old API. And all changes must be tested.
I feel our situation should be fairly common in software library development and API evolution. Surprisingly it took Java such long time (until Java 8) to fix the bug.
You can use the @SuppressWarnings annotation to suppress warnings whenever that code is compiled. Place the @SuppressWarnings annotation at the declaration of the class, method, field, or local variable that uses a deprecated API.
If we don't want to fix the warning, then we can suppress it with the @SuppressWarnings annotation. This annotation allows us to say which kinds of warnings to ignore. While warning types can vary by compiler vendor, the two most common are deprecation and unchecked.
Use of @SuppressWarnings is to suppress or ignore warnings coming from the compiler, i.e., the compiler will ignore warnings if any for that piece of code. 1. @SuppressWarnings("unchecked") public class Calculator { } - Here, it will ignore all unchecked warnings coming from that class.
It's important to note that deprecated code and obsolete code are two different things. Deprecated code generally continues to be used for legacy functionality, and the dependence is removed during a big release. Obsolete code, on the other hand, is already out of use.
I'm sorry to say that I don't have a solution to the problem you're facing, though as you've observed, there has been some progress. We've been trying to get rid of all the Java compilation warnings in the JDK itself, and this has been a long, difficult process. During JDK 8 development in 2011 I helped kick off the warnings cleanup effort and I later co-presented a JavaOne talk (slides and audio) on the subject.
More recently, my colleage Joe Darcy has continued the warnings cleanup work and has worked through the different warnings categories and has finally reached deprecation warnings. As you noted, there have been some bugs in the compiler's handling of suppression of deprecation warnings, such as JDK-6480588 which was fixed in JDK 8. Unfortunately, it is still not possible in JDK 8 to suppress warnings on imports of deprecated items. This bug, JDK-8032211, was fixed quite recently in our JDK 9 development line. In fact, we're still tuning up the handling of the @Deprecated
annotation. For example, bug JDK-6481080 clarifies that attempting to use @Deprecated
in a package-info.java
file does not in fact deprecate the package; this bug was fixed just last week. And there is more work to be done but it's somewhat speculative at this point.
The JDK is facing similar problems to yours, in that we have to maintain deprecated APIs for clients that are still using them. But since we use and implement such APIs internally, we have a lot of deprecation warnings to suppress. As of this writing, in our JDK 9 development line, we still have not been able to compile the system without deprecation warnings. As a result, the javac
options for lint warnings are still:
-Xlint:all,-deprecation
You will probably have to disable deprecation warnings in your compilation as well, especially if you are still building on JDK 6. I don't see a way around it at this point.
One final note on one of your deprecation cases:
@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass> { ... }
This does not issue a deprecation warning, nor should it. The Java Language Specification, section 9.6.4.6, specifies that deprecation warnings are not issued if the use of a deprecated entity is within an entity that is itself deprecated.
Consider using -Xmaxwarns, you can control how many warnings before stop.
Or try collect the number of warnings and fail the integration process, not compiling.
For example: https://issues.apache.org/jira/browse/HADOOP-11252. Every code commit to the hadoop project need to pass the automated CI and it give -1 for increase number of warnings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With