Source code analysis: calls to wrapper class constructors

Remi Forax forax at univ-mlv.fr
Tue Oct 27 20:00:08 UTC 2020


----- Mail original -----
> De: "daniel smith" <daniel.smith at oracle.com>
> À: "valhalla-spec-experts" <valhalla-spec-experts at openjdk.java.net>
> Envoyé: Mardi 27 Octobre 2020 20:27:39
> Objet: Re: Source code analysis: calls to wrapper class constructors

>> 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.

Three remarks:
- the compiler can warn because a code is using new Integer(value) or warn because the compiler will automatically transform all new Integer(value) to Integer.valueOf() once Valhalla is integrated,
  i prefer the second solution, having a warning message saying that in the future new Integer() will not be supported and that all new Integer(...) will be transformed by the compiler automatically to Integer.valueOf(). 
- the introduction of the strong encapsulation in 9 was a very similar challenge, the first thing to do is to raise awareness, having a warning at runtime (so emitted by the VM) per callsite using new Wrapper(...)
  will help a lot. People can detect easily if they are using a dependency that use something that will not be backward compatible (this warning should be emitted by Java 16+, because there is no point to wait
  and because of JEP 396, there will be a second wave of people wanting to update the library they maintain, so they can fixed both issues in one pass.
- IDE should inspect the jars downloaded by Maven and Gradle, and report the use of deprecated for removal APIs, again to raise awareness,
  a warning directly on the tag dependency in the POM saying that this dependency (or one of it's sub-dependencies) is using deprecated for removal APIs will help a lot. 

Rémi


More information about the valhalla-spec-observers mailing list