Source code analysis: calls to wrapper class constructors
Dan Smith
daniel.smith at oracle.com
Tue Oct 27 19:27:39 UTC 2020
> On Oct 19, 2020, at 6:01 PM, Dan Smith <daniel.smith at oracle.com> wrote:
>
> In the context of the Warnings for Value-Based Classes JEP, we're looking for usages of the deprecated wrapper class constructors ('new Integer(...)', 'new Double(...)', etc.). When do these get used? How often is this motivated by wanting a unique object vs. legacy code that has no particular reason not to use 'valueOf'?
>
> We've got some investigations going on at Oracle, including looking at some open-source projects, but I'm interested in examples from other companies/projects as well. Please investigate and share what you find!
>
> I'll reply in a few days with our analysis for the code we look at.
So, some conclusions that we've drawn:
- In 2020, the constructor calls are fairly pervasive, even in recently released binaries. Removing these constructors may be the most disruptive single API change we've ever made.
- The trend is good—serious projects have mostly responded to the deprecation warnings introduced in 9. In 2024 (for example), the picture may be much better.
- It is impossible, given the current JVM model for primitive classes, for Integer to both be a primitive class and support 'new java/lang/Integer'. Binaries calling the deprecated constructors simply won't work.
- There is a meaningful semantic difference, in terms of promising unique identity, between code that does 'new Integer' and code that does 'Integer.valueOf' or implicitly boxes. The latter is better aligned with the class's future behavior as a primitive class.
- Almost no usages care about the identity distinction—they just want boxing. But it's difficult to automatically detect the usages that do.
These points lead to the following tentative plan:
We'll proceed as planned with deprecation for removal. The message for all Java programs is to stop using these constructors if you want to run in future JDKs. Typically, the simplest refactoring is to replace 'new Integer(x)' with just 'x', but in some cases you might want 'Integer.valueOf(x)'. When you refactor, you should confirm that the change in identity semantics is acceptable.
We'll encourage IDEs to provide tooling for updating sources, including batch processing. (As an example, IntelliJ already highlights deprecated APIs and suggests conversions, although I'm not familiar with its batch processing features.)
For legacy binaries that have not been updated but that need to run on a future JDK, we'll provide tooling to rewrite their bytecode containing constructor calls, either as a preprocessing step on jar files, or as a runtime command-line argument.
This tooling will support common bytecode patterns like 'new Foo; dup; ...; invokespecial Foo.<init>;', but will not be a comprehensive solution. (Mimicking the behavior of instance initialization method invocation in full generality would be a very difficult task.) It will also carry behavioral compatibility risks. For these reasons, it will be available as a workaround, not as default JVM behavior.
More information about the valhalla-spec-observers
mailing list