8332086: Remove the usage of ServiceLoader in j.u.r.RandomGeneratorFactory

8332476: j.u.r.RandomGeneratorFactor.create(long|byte[]) should throw rather than silently fallback to no-arg create()

Reviewed-by: jpai
This commit is contained in:
Raffaello Giulietti 2024-05-21 12:53:03 +00:00
parent 5cf8288b80
commit 42e3c842ae
19 changed files with 337 additions and 397 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,6 @@
package java.security; package java.security;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
import sun.security.jca.GetInstance; import sun.security.jca.GetInstance;
import sun.security.jca.GetInstance.Instance; import sun.security.jca.GetInstance.Instance;
import sun.security.jca.Providers; import sun.security.jca.Providers;
@ -149,10 +148,6 @@ import java.util.regex.Pattern;
* @since 1.1 * @since 1.1
*/ */
@RandomGeneratorProperties(
name = "SecureRandom",
isStochastic = true
)
public class SecureRandom extends java.util.Random { public class SecureRandom extends java.util.Random {
private static final Debug pdebug = private static final Debug pdebug =

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,8 +32,6 @@ import java.util.stream.DoubleStream;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.LongStream; import java.util.stream.LongStream;
import jdk.internal.util.random.RandomSupport.*;
import static jdk.internal.util.random.RandomSupport.*; import static jdk.internal.util.random.RandomSupport.*;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
@ -77,11 +75,6 @@ import jdk.internal.misc.Unsafe;
* @author Frank Yellin * @author Frank Yellin
* @since 1.0 * @since 1.0
*/ */
@RandomGeneratorProperties(
name = "Random",
i = 48, j = 0, k = 0,
equidistribution = 0
)
public class Random implements RandomGenerator, java.io.Serializable { public class Random implements RandomGenerator, java.io.Serializable {
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -33,7 +33,6 @@ import java.util.stream.LongStream;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A generator of uniform pseudorandom values (with period 2<sup>64</sup>) * A generator of uniform pseudorandom values (with period 2<sup>64</sup>)
@ -87,11 +86,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @author Doug Lea * @author Doug Lea
* @since 1.8 * @since 1.8
*/ */
@RandomGeneratorProperties(
name = "SplittableRandom",
i = 64, j = 0, k = 0,
equidistribution = 1
)
public final class SplittableRandom implements RandomGenerator, SplittableGenerator { public final class SplittableRandom implements RandomGenerator, SplittableGenerator {
/* /*

View File

@ -85,12 +85,6 @@ import jdk.internal.misc.VM;
* @since 1.7 * @since 1.7
* @author Doug Lea * @author Doug Lea
*/ */
@RandomGeneratorProperties(
name = "ThreadLocalRandom",
i = 64, j = 0, k = 0,
equidistribution = 1
)
public final class ThreadLocalRandom extends Random { public final class ThreadLocalRandom extends Random {
/* /*
* This class implements the java.util.Random API (and subclasses * This class implements the java.util.Random API (and subclasses

View File

@ -25,24 +25,30 @@
package java.util.random; package java.util.random;
import java.lang.reflect.Constructor; import jdk.internal.random.L128X1024MixRandom;
import jdk.internal.random.L128X128MixRandom;
import jdk.internal.random.L128X256MixRandom;
import jdk.internal.random.L32X64MixRandom;
import jdk.internal.random.L64X1024MixRandom;
import jdk.internal.random.L64X128MixRandom;
import jdk.internal.random.L64X128StarStarRandom;
import jdk.internal.random.L64X256MixRandom;
import jdk.internal.random.Xoroshiro128PlusPlus;
import jdk.internal.random.Xoshiro256PlusPlus;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.AccessController; import java.security.SecureRandom;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.SplittableRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator; import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator;
import java.util.random.RandomGenerator.JumpableGenerator; import java.util.random.RandomGenerator.JumpableGenerator;
import java.util.random.RandomGenerator.LeapableGenerator; import java.util.random.RandomGenerator.LeapableGenerator;
import java.util.random.RandomGenerator.SplittableGenerator; import java.util.random.RandomGenerator.SplittableGenerator;
import java.util.random.RandomGenerator.StreamableGenerator; import java.util.random.RandomGenerator.StreamableGenerator;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* This is a factory class for generating multiple random number generators * This is a factory class for generating multiple random number generators
@ -107,137 +113,268 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* *
*/ */
public final class RandomGeneratorFactory<T extends RandomGenerator> { public final class RandomGeneratorFactory<T extends RandomGenerator> {
/**
* Instance provider class of random number algorithm.
*/
private final Provider<? extends RandomGenerator> provider;
/** private static final String DEFAULT_ALGORITHM = "L32X64MixRandom";
* Provider RandomGeneratorProperties annotation.
*/
private volatile RandomGeneratorProperties properties;
/** private record RandomGeneratorProperties(
* Default provider constructor. Class<? extends RandomGenerator> rgClass,
*/ String name,
private volatile Constructor<T> ctor; String group,
int i,
int j,
int k,
int equidistribution,
int flags) {
/** /* single bit masks composable with operator | */
* Provider constructor with long seed. private static final int INSTANTIABLE = 1 << 0;
*/ private static final int LONG_SEED = 1 << 1;
private Constructor<T> ctorLong; private static final int BYTE_ARRAY_SEED = 1 << 2;
private static final int STOCHASTIC = 1 << 3;
private static final int HARDWARE = 1 << 4;
private static final int DEPRECATED = 1 << 5;
/** private static final int ALL_CONSTRUCTORS = INSTANTIABLE | LONG_SEED | BYTE_ARRAY_SEED;
* Provider constructor with byte[] seed.
*/
private Constructor<T> ctorBytes;
private static final Map<String, RandomGeneratorProperties> FACTORY_MAP = createFactoryMap();
private static class FactoryMapHolder {
static final Map<String, Provider<? extends RandomGenerator>> FACTORY_MAP = createFactoryMap();
/** /**
* Returns the factory map, lazily constructing map on first use. * Returns the factory map, lazily constructing it on first use.
* <p> Although {@link ThreadLocalRandom} can only be accessed via
* {@link ThreadLocalRandom#current()}, a map entry is added nevertheless
* to record its properties that are otherwise not documented
* anywhere else.
* <p> Currently, no algorithm is deprecated.
* *
* @return Map of RandomGeneratorFactory classes. * @return Map of RandomGeneratorProperties.
*/ */
private static Map<String, Provider<? extends RandomGenerator>> createFactoryMap() { private static Map<String, RandomGeneratorProperties> createFactoryMap() {
FactoryMapHolder.class.getModule().addUses(RandomGenerator.class); return Map.ofEntries(
return ServiceLoader entry(SecureRandom.class, "SecureRandom", "Legacy",
.load(RandomGenerator.class, ClassLoader.getPlatformClassLoader()) 0, 0, 0, Integer.MAX_VALUE,
.stream() INSTANTIABLE | BYTE_ARRAY_SEED | STOCHASTIC | deprecationBit(SecureRandom.class)),
.filter(p -> !p.type().isInterface()) entry(Random.class, "Random", "Legacy",
.collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity())); 48, 0, 0, 0,
INSTANTIABLE | LONG_SEED | deprecationBit(Random.class)),
entry(SplittableRandom.class, "SplittableRandom", "Legacy",
64, 0, 0, 1,
INSTANTIABLE | LONG_SEED | deprecationBit(SplittableRandom.class)),
entry(L32X64MixRandom.class, "L32X64MixRandom", "LXM",
64, 1, 32, 1,
ALL_CONSTRUCTORS),
entry(L64X128MixRandom.class, "L64X128MixRandom", "LXM",
128, 1, 64, 2,
ALL_CONSTRUCTORS),
entry(L64X128StarStarRandom.class, "L64X128StarStarRandom", "LXM",
128, 1, 64, 2,
ALL_CONSTRUCTORS),
entry(L64X256MixRandom.class, "L64X256MixRandom", "LXM",
256, 1, 64, 4,
ALL_CONSTRUCTORS),
entry(L64X1024MixRandom.class, "L64X1024MixRandom", "LXM",
1024, 1, 64, 16,
ALL_CONSTRUCTORS),
entry(L128X128MixRandom.class, "L128X128MixRandom", "LXM",
128, 1, 128, 1,
ALL_CONSTRUCTORS),
entry(L128X256MixRandom.class, "L128X256MixRandom", "LXM",
256, 1, 128, 1,
ALL_CONSTRUCTORS),
entry(L128X1024MixRandom.class, "L128X1024MixRandom", "LXM",
1024, 1, 128, 1,
ALL_CONSTRUCTORS),
entry(Xoroshiro128PlusPlus.class, "Xoroshiro128PlusPlus", "Xoroshiro",
128, 1, 0, 1,
ALL_CONSTRUCTORS),
entry(Xoshiro256PlusPlus.class, "Xoshiro256PlusPlus", "Xoshiro",
256, 1, 0, 3,
ALL_CONSTRUCTORS),
entry(ThreadLocalRandom.class, "ThreadLocalRandom", "Legacy",
64, 0, 0, 1,
deprecationBit(ThreadLocalRandom.class))
);
}
private static Map.Entry<String, RandomGeneratorProperties> entry(
Class<? extends RandomGenerator> rgClass, String name, String group,
int i, int j, int k, int equidistribution,
int flags) {
return Map.entry(name,
new RandomGeneratorProperties(rgClass, name, group,
i, j, k, equidistribution,
flags));
}
private static int deprecationBit(Class<? extends RandomGenerator> rgClass) {
return rgClass.isAnnotationPresent(Deprecated.class) ? DEPRECATED : 0;
}
private RandomGenerator create() {
return switch (name) {
case "Random" -> new Random();
case "SecureRandom" -> new SecureRandom();
case "SplittableRandom" -> new SplittableRandom();
case "L32X64MixRandom" -> new L32X64MixRandom();
case "L64X128MixRandom" -> new L64X128MixRandom();
case "L64X128StarStarRandom" -> new L64X128StarStarRandom();
case "L64X256MixRandom" -> new L64X256MixRandom();
case "L64X1024MixRandom" -> new L64X1024MixRandom();
case "L128X128MixRandom" -> new L128X128MixRandom();
case "L128X256MixRandom" -> new L128X256MixRandom();
case "L128X1024MixRandom" -> new L128X1024MixRandom();
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus();
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus();
default -> throw new InternalError("should not happen");
};
}
private RandomGenerator create(long seed) {
if (isInstantiable() && (flags & LONG_SEED) == 0) {
throw new UnsupportedOperationException("Random algorithm "
+ name + " does not support a long seed");
}
return switch (name) {
case "Random" -> new Random(seed);
case "SplittableRandom" -> new SplittableRandom(seed);
case "L32X64MixRandom" -> new L32X64MixRandom(seed);
case "L64X128MixRandom" -> new L64X128MixRandom(seed);
case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed);
case "L64X256MixRandom" -> new L64X256MixRandom(seed);
case "L64X1024MixRandom" -> new L64X1024MixRandom(seed);
case "L128X128MixRandom" -> new L128X128MixRandom(seed);
case "L128X256MixRandom" -> new L128X256MixRandom(seed);
case "L128X1024MixRandom" -> new L128X1024MixRandom(seed);
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed);
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed);
default -> throw new InternalError("should not happen");
};
}
private RandomGenerator create(byte[] seed) {
if (isInstantiable() && (flags & BYTE_ARRAY_SEED) == 0) {
throw new UnsupportedOperationException("Random algorithm "
+ name + " does not support a byte[] seed");
}
return switch (name) {
case "SecureRandom" -> new SecureRandom(seed);
case "L32X64MixRandom" -> new L32X64MixRandom(seed);
case "L64X128MixRandom" -> new L64X128MixRandom(seed);
case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed);
case "L64X256MixRandom" -> new L64X256MixRandom(seed);
case "L64X1024MixRandom" -> new L64X1024MixRandom(seed);
case "L128X128MixRandom" -> new L128X128MixRandom(seed);
case "L128X256MixRandom" -> new L128X256MixRandom(seed);
case "L128X1024MixRandom" -> new L128X1024MixRandom(seed);
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed);
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed);
default -> throw new InternalError("should not happen");
};
}
private boolean isStochastic() {
return (flags & STOCHASTIC) != 0;
}
private boolean isHardware() {
return (flags & HARDWARE) != 0;
}
private boolean isInstantiable() {
return (flags & INSTANTIABLE) != 0;
}
private boolean isDeprecated() {
return (flags & DEPRECATED) != 0;
}
private BigInteger period() {
/*
* 0 if i = j = k = 0
* (2^i - j) 2^k otherwise
*/
return i == 0 && j == 0 && k == 0
? BigInteger.ZERO
: BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
}
private int stateBits() {
return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
} }
} }
/**
* Random generator properties.
*/
private final RandomGeneratorProperties properties;
/** /**
* Private constructor. * Private constructor.
* *
* @param provider Provider class to wrap. * @param properties Random generator properties.
*/ */
private RandomGeneratorFactory(Provider<? extends RandomGenerator> provider) { private RandomGeneratorFactory(RandomGeneratorProperties properties) {
this.provider = provider; this.properties = properties;
} }
/** /**
* Returns the factory map, lazily constructing map on first call. * Returns the factory map, lazily constructing the map on first call.
* *
* @return Map of RandomGeneratorFactory classes. * @return Map of random generator classes.
*/ */
private static Map<String, Provider<? extends RandomGenerator>> getFactoryMap() { private static Map<String, RandomGeneratorProperties> getFactoryMap() {
return FactoryMapHolder.FACTORY_MAP; return RandomGeneratorProperties.FACTORY_MAP;
} }
/** /**
* Return the annotation for the specified provider. * Return true if the random generator class is a subclass of the category.
*
* @return RandomGeneratorProperties annotation for the specified provider.
*/
private RandomGeneratorProperties getProperties() {
if (properties == null) {
synchronized (provider) {
if (properties == null) {
properties = provider.type().getDeclaredAnnotation(RandomGeneratorProperties.class);
Objects.requireNonNull(properties, provider.type() + " missing annotation");
}
}
}
return properties;
}
/**
* Return true if the provider is a subclass of the category.
* *
* @param category Interface category, sub-interface of {@link RandomGenerator}. * @param category Interface category, sub-interface of {@link RandomGenerator}.
* *
* @return true if the provider is a subclass of the category. * @return true if the random generator class is a subclass of the category.
*/ */
private boolean isSubclass(Class<? extends RandomGenerator> category) { private boolean isSubclass(Class<? extends RandomGenerator> category) {
return isSubclass(category, provider); return isSubclass(category, properties.rgClass());
} }
/** /**
* Return true if the provider is a subclass of the category. * Return true if rgClass is a subclass of the category.
* *
* @param category Interface category, sub-interface of {@link RandomGenerator}. * @param category Interface category, sub-interface of {@link RandomGenerator}.
* @param provider Provider that is being filtered. * @param rgClass Class that is being filtered.
* *
* @return true if the provider is a subclass of the category. * @return true if rgClass is a subclass of the category.
*/ */
private static boolean isSubclass(Class<? extends RandomGenerator> category, private static boolean isSubclass(Class<? extends RandomGenerator> category,
Provider<? extends RandomGenerator> provider) { Class<? extends RandomGenerator> rgClass) {
return provider != null && category.isAssignableFrom(provider.type()); return rgClass != null && category.isAssignableFrom(rgClass);
} }
/** /**
* Returns the provider matching name and category. * Returns a RandomGeneratorProperties instance matching name and category.
* *
* @param name Name of RandomGenerator * @param name Name of RandomGenerator
* @param category Interface category, sub-interface of {@link RandomGenerator}. * @param category Interface category, sub-interface of {@link RandomGenerator}.
* * @return A RandomGeneratorProperties instance matching name and category.
* @return A provider matching name and category. * @throws IllegalArgumentException if the resulting type is not a subclass of category.
*
* @throws IllegalArgumentException if provider is not a subclass of category.
*/ */
private static Provider<? extends RandomGenerator> findProvider(String name, private static RandomGeneratorProperties findClass(String name,
Class<? extends RandomGenerator> category) Class<? extends RandomGenerator> category) throws IllegalArgumentException {
throws IllegalArgumentException { RandomGeneratorProperties properties = name != null
Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap(); ? getFactoryMap().get(name)
Provider<? extends RandomGenerator> provider = fm.get(name); : null;
if (provider == null) { if (properties == null || !properties.isInstantiable()) {
throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" + throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" +
name + name +
"\" is available"); "\" is available");
} else if (!isSubclass(category, provider)) {
throw new IllegalArgumentException("The random number generator algorithm \"" +
name +
"\" is not implemented with the interface \"" +
category.getSimpleName() +
"\"");
} }
return provider; if (!isSubclass(category, properties.rgClass())) {
throw new IllegalArgumentException("The random number generator algorithm \"" +
name +
"\" is not implemented with the interface \"" +
category.getSimpleName() +
"\"");
}
return properties;
} }
/** /**
@ -255,8 +392,8 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
static <T extends RandomGenerator> T of(String name, Class<T> category) static <T extends RandomGenerator> T of(String name, Class<T> category)
throws IllegalArgumentException { throws IllegalArgumentException {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
T uncheckedRandomGenerator = (T)findProvider(name, category).get(); T instance = (T) findClass(name, category).create();
return uncheckedRandomGenerator; return instance;
} }
/** /**
@ -273,68 +410,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
*/ */
static <T extends RandomGenerator> RandomGeneratorFactory<T> factoryOf(String name, Class<T> category) static <T extends RandomGenerator> RandomGeneratorFactory<T> factoryOf(String name, Class<T> category)
throws IllegalArgumentException { throws IllegalArgumentException {
Provider<? extends RandomGenerator> uncheckedProvider = findProvider(name, category); return new RandomGeneratorFactory<>(findClass(name, category));
return new RandomGeneratorFactory<>(uncheckedProvider);
}
/**
* Fetch the required constructors for class of random number algorithm.
*
* @param randomGeneratorClass class of random number algorithm (provider)
*/
private void getConstructors(Class<? extends RandomGenerator> randomGeneratorClass) {
if (ctor == null) {
synchronized (provider) {
if (ctor == null) {
PrivilegedExceptionAction<Constructor<?>[]> ctorAction = randomGeneratorClass::getConstructors;
try {
@SuppressWarnings("removal")
Constructor<?>[] ctors = AccessController.doPrivileged(ctorAction);
Constructor<T> tmpCtor = null;
Constructor<T> tmpCtorLong = null;
Constructor<T> tmpCtorBytes = null;
for (Constructor<?> ctorGeneric : ctors) {
@SuppressWarnings("unchecked")
Constructor<T> ctorSpecific = (Constructor<T>) ctorGeneric;
final Class<?>[] parameterTypes = ctorSpecific.getParameterTypes();
if (parameterTypes.length == 0) {
tmpCtor = ctorSpecific;
} else if (parameterTypes.length == 1) {
Class<?> argType = parameterTypes[0];
if (argType == long.class) {
tmpCtorLong = ctorSpecific;
} else if (argType == byte[].class) {
tmpCtorBytes = ctorSpecific;
}
}
}
if (tmpCtor == null) {
throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor");
}
// Store specialized constructors first, guarded by ctor
ctorBytes = tmpCtorBytes;
ctorLong = tmpCtorLong;
ctor = tmpCtor;
} catch (PrivilegedActionException ex) {
// Do nothing
}
}
}
}
}
/**
* Ensure all the required constructors are fetched.
*/
private void ensureConstructors() {
getConstructors(provider.type());
} }
/** /**
@ -355,7 +431,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
Objects.requireNonNull(name); Objects.requireNonNull(name);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
RandomGeneratorFactory<T> factory = RandomGeneratorFactory<T> factory =
(RandomGeneratorFactory<T>)factoryOf(name, RandomGenerator.class); (RandomGeneratorFactory<T>) factoryOf(name, RandomGenerator.class);
return factory; return factory;
} }
@ -369,23 +445,21 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return a {@link RandomGeneratorFactory} * @return a {@link RandomGeneratorFactory}
*/ */
public static RandomGeneratorFactory<RandomGenerator> getDefault() { public static RandomGeneratorFactory<RandomGenerator> getDefault() {
return factoryOf("L32X64MixRandom", RandomGenerator.class); return factoryOf(DEFAULT_ALGORITHM, RandomGenerator.class);
} }
/** /**
* Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}. * Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
* <p> *
* RandomGenerators that are marked as deprecated are not included in the result. * RandomGenerators that are marked as deprecated are not included in the result.
* *
* @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}. * @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
*/ */
public static Stream<RandomGeneratorFactory<RandomGenerator>> all() { public static Stream<RandomGeneratorFactory<RandomGenerator>> all() {
Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap(); return getFactoryMap().values()
return fm.values() .stream()
.stream() .filter(p -> p.isInstantiable() && !p.isDeprecated())
.filter(p -> !p.type().isAnnotationPresent(Deprecated.class) && .map(RandomGeneratorFactory::new);
p.type().isAnnotationPresent(RandomGeneratorProperties.class))
.map(RandomGeneratorFactory::new);
} }
/** /**
@ -395,7 +469,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return Name of the <a href="package-summary.html#algorithms">algorithm</a>. * @return Name of the <a href="package-summary.html#algorithms">algorithm</a>.
*/ */
public String name() { public String name() {
return provider.type().getSimpleName(); return properties.name();
} }
/** /**
@ -405,7 +479,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return Group name of the <a href="package-summary.html#algorithms">algorithm</a>. * @return Group name of the <a href="package-summary.html#algorithms">algorithm</a>.
*/ */
public String group() { public String group() {
return getProperties().group(); return properties.group();
} }
/** /**
@ -416,11 +490,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* to maintain state of seed. * to maintain state of seed.
*/ */
public int stateBits() { public int stateBits() {
RandomGeneratorProperties properties = getProperties(); return properties.stateBits();
int i = properties.i();
int k = properties.k();
return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
} }
/** /**
@ -429,7 +499,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>. * @return the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
*/ */
public int equidistribution() { public int equidistribution() {
return getProperties().equidistribution(); return properties.equidistribution();
} }
/** /**
@ -440,16 +510,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return BigInteger period. * @return BigInteger period.
*/ */
public BigInteger period() { public BigInteger period() {
RandomGeneratorProperties properties = getProperties(); return properties.period();
int i = properties.i();
int j = properties.j();
int k = properties.k();
if (i == 0 && j == 0 && k == 0) {
return BigInteger.ZERO;
} else {
return BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
}
} }
/** /**
@ -460,7 +521,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return true if random generator is statistical. * @return true if random generator is statistical.
*/ */
public boolean isStatistical() { public boolean isStatistical() {
return !getProperties().isStochastic(); return !properties.isStochastic();
} }
/** /**
@ -470,7 +531,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return true if random generator is stochastic. * @return true if random generator is stochastic.
*/ */
public boolean isStochastic() { public boolean isStochastic() {
return getProperties().isStochastic(); return properties.isStochastic();
} }
/** /**
@ -480,7 +541,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* @return true if random generator is generated by hardware. * @return true if random generator is generated by hardware.
*/ */
public boolean isHardware() { public boolean isHardware() {
return getProperties().isHardware(); return properties.isHardware();
} }
/** /**
@ -547,66 +608,64 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
* marked for deprecation * marked for deprecation
*/ */
public boolean isDeprecated() { public boolean isDeprecated() {
return provider.type().isAnnotationPresent(Deprecated.class); return properties.isDeprecated();
} }
/** /**
* Create an instance of {@link RandomGenerator} based on * Create an instance of {@link RandomGenerator} based on the
* <a href="package-summary.html#algorithms">algorithm</a> chosen. * <a href="package-summary.html#algorithms">algorithm</a> chosen.
* *
* @return new in instance of {@link RandomGenerator}. * @return new instance of {@link RandomGenerator}.
*
*/ */
public T create() { public T create() {
try { @SuppressWarnings("unchecked")
ensureConstructors(); T instance = (T) properties.create();
return ctor.newInstance(); return instance;
} catch (Exception ex) {
// Should never happen.
throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor", ex);
}
} }
/** /**
* Create an instance of {@link RandomGenerator} based on * Create an instance of {@link RandomGenerator} based on the
* <a href="package-summary.html#algorithms">algorithm</a> chosen * <a href="package-summary.html#algorithms">algorithm</a> chosen,
* providing a starting long seed. If long seed is not supported by an * and the provided {@code seed}.
* algorithm then the no argument form of create is used. * If the {@link RandomGenerator} doesn't support instantiation through
* a {@code seed} of type {@code long} then this method throws
* an {@link UnsupportedOperationException}.
* *
* @param seed long random seed value. * @param seed long random seed value.
* *
* @return new in instance of {@link RandomGenerator}. * @return new instance of {@link RandomGenerator}.
*
* @throws UnsupportedOperationException
* if a {@code seed} of type {@code long} in not supported.
*/ */
public T create(long seed) { public T create(long seed) {
try { @SuppressWarnings("unchecked")
ensureConstructors(); T instance = (T) properties.create(seed);
return ctorLong.newInstance(seed); return instance;
} catch (Exception ex) {
return create();
}
} }
/** /**
* Create an instance of {@link RandomGenerator} based on * Create an instance of {@link RandomGenerator} based on the
* <a href="package-summary.html#algorithms">algorithm</a> chosen * <a href="package-summary.html#algorithms">algorithm</a> chosen,
* providing a starting byte[] seed. If byte[] seed is not supported by an * and the provided {@code seed}.
* <a href="package-summary.html#algorithms">algorithm</a> then the no * If the {@link RandomGenerator} doesn't support instantiation through
* argument form of create is used. * a {@code seed} of type {@code byte[]} then this method throws
* an {@link UnsupportedOperationException}.
* *
* @param seed byte array random seed value. * @param seed byte array random seed value.
* *
* @return new in instance of {@link RandomGenerator}. * @return new instance of {@link RandomGenerator}.
*
* @throws UnsupportedOperationException
* if a {@code seed} of type {@code byte[]} in not supported.
* *
* @throws NullPointerException if seed is null. * @throws NullPointerException if seed is null.
*/ */
public T create(byte[] seed) { public T create(byte[] seed) {
Objects.requireNonNull(seed, "seed must not be null"); Objects.requireNonNull(seed, "seed must not be null");
try { @SuppressWarnings("unchecked")
ensureConstructors(); T instance = (T) properties.create(seed);
return ctorBytes.newInstance(seed); return instance;
} catch (Exception ex) {
return create();
}
} }
} }

View File

@ -81,8 +81,8 @@
* <blockquote>{@code import java.util.random.*;}</blockquote> * <blockquote>{@code import java.util.random.*;}</blockquote>
* *
* Then one can choose a specific implementation by giving the name of a generator * Then one can choose a specific implementation by giving the name of a generator
* algorithm to the static method {@link RandomGenerator#of}, in which case the * algorithm to the static method {@link RandomGenerator#of}, in which case
* no-arguments constructor for that implementation is used: * a {@link RandomGenerator} is constructed without any seed value:
* *
* <blockquote>{@code RandomGenerator g = RandomGenerator.of("L64X128MixRandom");}</blockquote> * <blockquote>{@code RandomGenerator g = RandomGenerator.of("L64X128MixRandom");}</blockquote>
* *
@ -125,8 +125,8 @@
* *
* <h2>Choosing a Random Number Generator Algorithm</h2> * <h2>Choosing a Random Number Generator Algorithm</h2>
* *
* <p> There are three groups of random number generator algorithm provided * <p> Random number generator algorithms are organized in groups,
* in Java: the Legacy group, the LXM group, and the Xoroshiro/Xoshiro group. * as described {@linkplain java.util.random##algorithms below}.
* *
* <p> The legacy group includes random number generators that existed * <p> The legacy group includes random number generators that existed
* before JDK 17: Random, ThreadLocalRandom, SplittableRandom, and * before JDK 17: Random, ThreadLocalRandom, SplittableRandom, and
@ -304,6 +304,13 @@
* <td style="text-align:right">1</td> * <td style="text-align:right">1</td>
* </tr> * </tr>
* <tr> * <tr>
* <th scope="row" style="text-align:left">SecureRandom</th>
* <td style="text-align:left">Legacy</td>
* <td style="text-align:left">BigInteger.ZERO</td>
* <td style="text-align:right">Integer.MAX_VALUE</td>
* <td style="text-align:right">Integer.MAX_VALUE</td>
* </tr>
* <tr>
* <th scope="row" style="text-align:left">ThreadLocalRandom <sup>*</sup></th> * <th scope="row" style="text-align:left">ThreadLocalRandom <sup>*</sup></th>
* <td style="text-align:left">Legacy</td> * <td style="text-align:left">Legacy</td>
* <td style="text-align:left">BigInteger.ONE.shiftLeft(64)</td> * <td style="text-align:left">BigInteger.ONE.shiftLeft(64)</td>

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L128X1024MixRandom",
group = "LXM",
i = 1024, j = 1, k = 128,
equidistribution = 1
)
public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerator { public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L128X128MixRandom",
group = "LXM",
i = 128, j = 1, k = 128,
equidistribution = 1
)
public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerator { public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L128X256MixRandom",
group = "LXM",
i = 256, j = 1, k = 128,
equidistribution = 1
)
public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerator { public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L32X64MixRandom",
group = "LXM",
i = 64, j = 1, k = 32,
equidistribution = 1
)
public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator { public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*
* Implementation Overview. * Implementation Overview.

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L64X1024MixRandom",
group = "LXM",
i = 1024, j = 1, k = 64,
equidistribution = 16
)
public final class L64X1024MixRandom extends AbstractSplittableWithBrineGenerator { public final class L64X1024MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L64X128MixRandom",
group = "LXM",
i = 128, j = 1, k = 64,
equidistribution = 2
)
public final class L64X128MixRandom extends AbstractSplittableWithBrineGenerator { public final class L64X128MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L64X128StarStarRandom",
group = "LXM",
i = 128, j = 1, k = 64,
equidistribution = 2
)
public final class L64X128StarStarRandom extends AbstractSplittableWithBrineGenerator { public final class L64X128StarStarRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "splittable" pseudorandom number generator (PRNG) whose period * A "splittable" pseudorandom number generator (PRNG) whose period
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "L64X256MixRandom",
group = "LXM",
i = 256, j = 1, k = 64,
equidistribution = 4
)
public final class L64X256MixRandom extends AbstractSplittableWithBrineGenerator { public final class L64X256MixRandom extends AbstractSplittableWithBrineGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import java.util.random.RandomGenerator.LeapableGenerator; import java.util.random.RandomGenerator.LeapableGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period * A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
@ -72,12 +71,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "Xoroshiro128PlusPlus",
group = "Xoroshiro",
i = 128, j = 1, k = 0,
equidistribution = 1
)
public final class Xoroshiro128PlusPlus implements LeapableGenerator { public final class Xoroshiro128PlusPlus implements LeapableGenerator {
/* /*

View File

@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.random.RandomGenerator; import java.util.random.RandomGenerator;
import java.util.random.RandomGenerator.LeapableGenerator; import java.util.random.RandomGenerator.LeapableGenerator;
import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport;
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
/** /**
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period * A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
@ -87,12 +86,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
* @since 17 * @since 17
* *
*/ */
@RandomGeneratorProperties(
name = "Xoshiro256PlusPlus",
group = "Xoshiro",
i = 256, j = 1, k = 0,
equidistribution = 3
)
public final class Xoshiro256PlusPlus implements LeapableGenerator { public final class Xoshiro256PlusPlus implements LeapableGenerator {
/* /*

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,10 +25,7 @@
package jdk.internal.util.random; package jdk.internal.util.random;
import java.lang.annotation.*;
import java.math.BigInteger;
import java.util.Objects; import java.util.Objects;
import java.util.Random;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.DoubleConsumer; import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
@ -53,49 +50,6 @@ import java.util.stream.StreamSupport;
* @since 17 * @since 17
*/ */
public class RandomSupport { public class RandomSupport {
/**
* Annotation providing RandomGenerator properties.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RandomGeneratorProperties {
/**
* Name of algorithm.
*/
String name();
/**
* Category of algorithm.
*/
String group() default "Legacy";
/**
* Algorithm period defined as:
*
* BigInteger.ONE.shiftLeft(i)
* .subtract(j)
* .shiftLeft(k)
*/
int i() default 0;
int j() default 0;
int k() default 0;
/**
* The equidistribution of the algorithm.
*/
int equidistribution() default Integer.MAX_VALUE;
/**
* Is the algorithm based on entropy (true random.)
*/
boolean isStochastic() default false;
/**
* Is the algorithm assisted by hardware (fast true random.)
*/
boolean isHardware() default false;
}
/* /*
* Implementation Overview. * Implementation Overview.
* *

View File

@ -419,19 +419,4 @@ module java.base {
provides java.nio.file.spi.FileSystemProvider with provides java.nio.file.spi.FileSystemProvider with
jdk.internal.jrtfs.JrtFileSystemProvider; jdk.internal.jrtfs.JrtFileSystemProvider;
provides java.util.random.RandomGenerator with
java.security.SecureRandom,
java.util.Random,
java.util.SplittableRandom,
jdk.internal.random.L32X64MixRandom,
jdk.internal.random.L64X128MixRandom,
jdk.internal.random.L64X128StarStarRandom,
jdk.internal.random.L64X256MixRandom,
jdk.internal.random.L64X1024MixRandom,
jdk.internal.random.L128X128MixRandom,
jdk.internal.random.L128X256MixRandom,
jdk.internal.random.L128X1024MixRandom,
jdk.internal.random.Xoroshiro128PlusPlus,
jdk.internal.random.Xoshiro256PlusPlus;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -87,7 +87,7 @@ public class RandomTestCoverage {
DoubleStream doubleStream4 = rng.doubles(5, 0.5, 1.0); DoubleStream doubleStream4 = rng.doubles(5, 0.5, 1.0);
} }
static void checkPredicates(RandomGeneratorFactory factory) { static void checkPredicates(RandomGeneratorFactory<RandomGenerator> factory) {
RandomGenerator rng = factory.create(); RandomGenerator rng = factory.create();
if (rng instanceof ArbitrarilyJumpableGenerator != factory.isArbitrarilyJumpable()) { if (rng instanceof ArbitrarilyJumpableGenerator != factory.isArbitrarilyJumpable()) {
throw new RuntimeException("isArbitrarilyJumpable failing"); throw new RuntimeException("isArbitrarilyJumpable failing");
@ -156,7 +156,7 @@ public class RandomTestCoverage {
coverFactory(RandomGeneratorFactory.of(name)); coverFactory(RandomGeneratorFactory.of(name));
} }
static void coverFactory(RandomGeneratorFactory factory) { static void coverFactory(RandomGeneratorFactory<RandomGenerator> factory) {
String name = factory.name(); String name = factory.name();
String group = factory.group(); String group = factory.group();
int stateBits = factory.stateBits(); int stateBits = factory.stateBits();
@ -171,8 +171,34 @@ public class RandomTestCoverage {
boolean isSplittable = factory.isSplittable(); boolean isSplittable = factory.isSplittable();
coverRandomGenerator(factory.create()); coverRandomGenerator(factory.create());
coverRandomGenerator(factory.create(12345L)); // test create(long)
coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8})); switch (factory.name()) {
// SecureRandom doesn't have long constructors so we expect
// UnsupportedOperationException
case "SecureRandom" -> {
try {
factory.create(12345L);
throw new AssertionError("RandomGeneratorFactory.create(long) was expected" +
"to throw UnsupportedOperationException for " + factory.name() + " but didn't");
} catch (UnsupportedOperationException ignored) {
}
}
default -> coverRandomGenerator(factory.create(12345L));
}
// test create(byte[])
switch (factory.name()) {
// these don't have byte[] constructors so we expect UnsupportedOperationException
case "Random",
"SplittableRandom" -> {
try {
factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8});
throw new AssertionError("RandomGeneratorFactory.create(byte[]) was expected" +
"to throw UnsupportedOperationException for " + factory.name() + " but didn't");
} catch (UnsupportedOperationException ignored) {
}
}
default -> coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}));
}
} }
static void coverDefaults() { static void coverDefaults() {
@ -188,32 +214,35 @@ public class RandomTestCoverage {
coverOf(factory.name()); coverOf(factory.name());
}); });
RandomGeneratorFactory.all() RandomGeneratorFactory.all()
.filter(f -> f.isStreamable()) .filter(RandomGeneratorFactory::isStreamable)
.forEach(factory -> { .forEach(factory -> {
coverStreamable((StreamableGenerator)factory.create()); coverStreamable((StreamableGenerator)factory.create());
}); });
RandomGeneratorFactory.all() RandomGeneratorFactory.all()
.filter(f -> f.isSplittable()) .filter(RandomGeneratorFactory::isSplittable)
.forEach(factory -> { .forEach(factory -> {
coverSplittable((SplittableGenerator)factory.create()); coverSplittable((SplittableGenerator)factory.create());
}); });
RandomGeneratorFactory.all() RandomGeneratorFactory.all()
.filter(f -> f.isJumpable()) .filter(RandomGeneratorFactory::isJumpable)
.forEach(factory -> { .forEach(factory -> {
coverJumpable((JumpableGenerator)factory.create()); coverJumpable((JumpableGenerator)factory.create());
}); });
RandomGeneratorFactory.all() RandomGeneratorFactory.all()
.filter(f -> f.isLeapable()) .filter(RandomGeneratorFactory::isLeapable)
.forEach(factory -> { .forEach(factory -> {
coverLeapable((LeapableGenerator)factory.create()); coverLeapable((LeapableGenerator)factory.create());
}); });
RandomGeneratorFactory.all() RandomGeneratorFactory.all()
.filter(f -> f.isArbitrarilyJumpable()) .filter(RandomGeneratorFactory::isArbitrarilyJumpable)
.forEach(factory -> { .forEach(factory -> {
coverArbitrarilyJumpable((ArbitrarilyJumpableGenerator)factory.create()); coverArbitrarilyJumpable((ArbitrarilyJumpableGenerator)factory.create());
}); });
RandomGeneratorFactory.all()
.forEach(RandomTestCoverage::checkPredicates);
coverRandomGenerator(new SecureRandom()); coverRandomGenerator(new SecureRandom());
coverRandomGenerator(ThreadLocalRandom.current()); coverRandomGenerator(ThreadLocalRandom.current());
coverDefaults();
} }
} }