Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Deprecated APIs and SuppressWarnings "deprecation" - practical approach

I have seen many examples of using the Deprecated annotation on APIs in order to mark them as 'need to be replaced soon'.

However, in almost all of these cases the code developers not only kept using the deprecated APIs, but also suppressed the deprecation warning.

It seems like the best intentions of the API developers end up creating more code which is irrelevant to the implemented business logic - if an API is deprecated but is continually used with the associated warnings being suppressed it seems like a degradation of the code at best and a potential application breaking point when replacing deprecated libraries at worst IMHO.

Is there a practical solution to this problem? At the very least, a way to tag this occurrence as a code smell, if it indeed stays for a relatively long time in the CR?

Please suggest an actual solution you might be using (library, SCA, CR plugin, etc.....)

Are there any planned JRE/JDK features that might help with this situation? My research has currently not found anything.

References:

  • what is the best way to comment a deprecated class in java
  • is it wrong to use deprecated api
  • Excluding warnings using @SuppressWarnings
  • Use @Deprecated Java class without compilation warning
like image 969
Rann Lifshitz Avatar asked May 12 '18 04:05

Rann Lifshitz


2 Answers

Step 1: Announce the removal

One may think that deprecating an API means announcing it will be removed, but this is not the only use case (as described in relevant articles of e.g. Java 7 and Java 9):

  • The API is dangerous (for example, the Thread.stop method).

  • There is a simple rename (for example, AWT Component.show/hide replaced by setVisible).

  • A newer, better API can be used instead.

  • The deprecated API is going to be removed.

To further complicate things, before Java 9, no deprecated API in the JDK was ever removed (see 20 Years Of Java Deprecation), so it is understandable if developers do not take deprecation seriously - neither in the JDK nor elsewhere.

Therefore, you need to communicate clearly that the API is really, really going to be removed. The way to do this depends on the version of Java your API is compiled with.

Java 8 or lower

In these Java versions, there is no formal way to explicitly distinguish the various deprecation use cases. The best you can do is adding the Javadoc tag @deprecated and not only giving the reason of deprecation and listing alternatives, but also explicitly announcing your intention to remove the API.

Java 9 or above

Since Java 9, with Enhanced Deprecation, you can now write

@Deprecated(forRemoval=<boolean>)

to explicitly document your intention. I think that together with Javadoc @deprecated (which should detail the reason for deprecation and list alternatives), this standardized flag is a fair warning.

With this flag set to true, the compiler will warn for each use of the deprecated element like this:

YourClass.java:<line>: warning: [removal] <method> in <class> has been
deprecated and marked for removal

This warning is enabled by default (instead of having to be enabled with -Xlint:deprecation) and is not suppressed with @SuppressWarnings("deprecation"). Instead, one would have to suppress it with the new @SuppressWarnings("removal"), which might make developers think twice about doing so without a really good reason.

Additionally, you can explicitly state the library version which introduced the deprecation with

@Deprecated(since="<version>")

Seeing this in Javadoc or the sources can help developers assess how urgent it is update their code.

Step 2a: Runtime warning

If feasible for the situation, add a runtime reminder: when the deprecated API is used, have it log a warning to the console or log file (using whatever logging mechanism you use) announcing that this will no longer work with the next major release. To avoid spam, you could only log that once (e.g. private static boolean warningLogged).

Step 2b: Static code analysis

Static code analyzers like SonarQube (also available as a hosted service) can be set up to flag each of these warnings. The SonarQube rule "deprecated code should not be used" should even work if the compiler's deprecation usage warning is suppressed.

SonarQube also tracks when a certain issue (i.e. a rule violation) was introduced (based on version control) and you can interactively filter its issue lists based on that date. For example, you could list all usages of deprecated code that have been in your code base for over a year so that you can prioritize work on fixing them.

Step 3: Remove the API

Not actually removing the API would give your API users the impression that they don't need to bother changing their code.

like image 79
Jens Bannmann Avatar answered Sep 28 '22 02:09

Jens Bannmann


A deprecated API is not useful just as far as it is annotated with @Deprecated. If the API clients can still successfully use it after years of it being marked as deprecated, then it's right to say that the API provider isn't helping them in any practical way.

Is there a practical solution to this problem?

Yes: let deprecation mean deprecation and after a grace period, make the deprecated API unavailable, if removal is the correct way to deal with it. If, for example, you deprecate an API with security risks, not removing it in a future release makes deprecation useless and can be seen as contributing to the problem.

The @Deprecated annotation is little more than documentation, which, even as you noted, other developers can simply ignore.

Java 9+ deprecation is perhaps more informative, but the end decision is still up to the developer consuming the API, which doesn't solve the problem.

like image 25
ernest_k Avatar answered Sep 28 '22 03:09

ernest_k