JDK-8265137 : java.util.Random suddenly has new public methods nowhere documented
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 17
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2021-04-13
  • Updated: 2024-04-30
  • Resolved: 2021-05-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17
17 b21Fixed
Related Reports
CSR :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
while investigating some  issues with build 17 of openJDK in combination with the forbiddenapis Maven/Gradle plugin I noticed that starting with JDK 17 b17 java.util.Random now extends some internal class of some jdk.internal package (jdk.internal.util.random.RandomSupport.AbstractSpliteratorGenerator). This is not really great, but shows what the module system can do. Tools owners (like forbiddenapis) have to work around that until full module system support is there.

But the extension of class jdk.internal.util.random.RandomSupport.AbstractSpliteratorGenerator brings some other problems: As the class is in another package, it implements some public methods (with some intro comment "Required by AbstractSpliteratorGenerator" - so implementor knows that's something strange): https://github.com/openjdk/jdk/blob/a0ec2cb289463969509fe508836e3faf789f46d8/src/java.base/share/classes/java/util/Random.java#L618-L626

Those methods are marked by the Javadoc tag @hidden. So they are nowhere documented and are implementation details. But those methods are still visible as public methods and also shown by IDE tools during autocomplete!

The following code compiles!!!:

import java.util.Random;

public class RandomTest { 
  public static void main(String... args) {
    new Random().makeLongsSpliterator(0L, 10L, 1L, 5L);
  } 
}

This should not be possible, as makeLongsSpliterator is nowhere documented, so code may accidentally use it.

I have not looked at the other implementations like SecureRandom and others, but I suspect they have the same problem.

IMHO, the code should not extend this internal abstract class and instead use a private implementation of the the abstract class and just delegate to it. It should also declare "implements RandomGenerator" directly. Reading the code is too confusing!

The current class design with extending classes hidden in other modules and implementing partially hiden methods is not a good thing, so please fix this!
Comments
Changeset: 05e60174 Author: Jim Laskey <jlaskey@openjdk.org> Date: 2021-05-04 11:53:07 +0000 URL: https://git.openjdk.java.net/jdk/commit/05e601748a35de02a33721199a00a3d6c335c6d9
04-05-2021

Hi David, this is right, but not different from the previous approach (public methods added to non-final class). The new PR looks like an improvement to me, so the visibility is reduced. The main problem here is that the hidden superclass should be package private, but this does not work, because subclasses of Random and the RandomGenerator are in many different packages, so it is hard to find a good place. But yes, I tried it out: You can subclass Random and override that method. Solution: make the protected implementations final.
14-04-2021

This is ringing some CSR alarm bells for me. You can't just add protected methods to non-final public classes either, without recognising that this is an API change.
14-04-2021

Why are makeLongsSpliterator() and others not declared "protected" in the abstract class. Their intention is to be just used by subclasses. This would also fix the issue!
13-04-2021