All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.exparity.stub.random.RandomBuilder Maven / Gradle / Ivy

Go to download

A Java library to support creation of test stubs. The library can create complete object graphs populated completely randomly, or can be populated with a mix of random and configured values.

There is a newer version: 2.0.8
Show newest version
package org.exparity.stub.random;

import static org.apache.commons.lang.RandomStringUtils.*;
import static org.apache.commons.lang.math.RandomUtils.*;
import static org.apache.commons.lang.time.DateUtils.addSeconds;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.exparity.stub.bean.BeanBuilder;
import org.exparity.stub.bean.BeanBuilderException;
import org.exparity.stub.core.ValueFactories;
import org.exparity.stub.core.ValueFactory;
import org.exparity.stub.core.ValueFactoryException;

/**
 * Builder object for instantiating and populating random instances of Java
 * types.
 * 
 * @author Stewart Bissett
 */
public abstract class RandomBuilder {

	/**
	 * Interface to be implemented by all classes which can restrict the
	 * behaviour of the random builder and how it assigns values to properties,
	 * which types, it creates, etc
	 */
	@FunctionalInterface
	public static interface RandomRestriction {

		/**
		 * Apply the restriction to the {@link BeanBuilder} instance.
		 * 
		 * @param the
		 *            instance to apply the restriction to
		 */
		public void applyTo(final BeanBuilder builder);
	}

	@SuppressWarnings({ "rawtypes", "serial" })
	private static final Map RANDOM_FACTORIES = new HashMap() {

		{
			put(Short.class, ValueFactories.aRandomShort());
			put(short.class, ValueFactories.aRandomShort());
			put(Integer.class, ValueFactories.aRandomInteger());
			put(int.class, ValueFactories.aRandomInteger());
			put(Long.class, ValueFactories.aRandomLong());
			put(long.class, ValueFactories.aRandomLong());
			put(Double.class, ValueFactories.aRandomDouble());
			put(double.class, ValueFactories.aRandomDouble());
			put(Float.class, ValueFactories.aRandomFloat());
			put(float.class, ValueFactories.aRandomFloat());
			put(Boolean.class, ValueFactories.aRandomBoolean());
			put(boolean.class, ValueFactories.aRandomBoolean());
			put(Byte.class, ValueFactories.aRandomByte());
			put(byte.class, ValueFactories.aRandomByte());
			put(Character.class, ValueFactories.aRandomChar());
			put(char.class, ValueFactories.aRandomChar());
			put(String.class, ValueFactories.aRandomString());
			put(BigDecimal.class, ValueFactories.aRandomDecimal());
			put(Date.class, ValueFactories.aRandomDate());
		}
	};

	private static final int DEFAULT_MAX_ARRAY_SIZE = 10;
	private static final int DEFAULT_MIN_ARRAY_SIZE = 2;
	private static final int MAX_STRING_LENGTH = 50;
	private static final int MINUTES_PER_HOUR = 60;
	private static final int HOURS_PER_DAY = 24;
	private static final int DAYS_PER_YEAR = 365;
	private static final int SECONDS_IN_A_YEAR = MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_PER_YEAR;

	/**
	 * Build a random {@link String} containing alphanumeric characters. For
	 * example
	 * 

* * String aRandomName = RandomBuilder.aRandomString(); * * * @return a random {@link String}. */ public static String aRandomString() { return randomAlphanumeric(MAX_STRING_LENGTH); } /** * Build a random {@link String} containing alphanumeric characters of the * specfied size. For example *

* * String aRandomName = RandomBuilder.aRandomString(10); * * * @return a random {@link String}. */ public static String aRandomString(final int length) { return randomAlphanumeric(length); } /** * Build a random {@link Integer}. For example *

* * Integer aRandomAge = RandomBuilder.aRandomInteger(); * * * @return a random {@link Integer}. */ public static Integer aRandomInteger() { return Integer.valueOf(nextInt()); } /** * Build a random {@link Integer} within the supplied minumum and maximum * range. For example *

* * Integer aRandomAge = RandomBuilder.aRandomInteger(1,100); * * * @param min * the minimum value can be * @param max * the maximum value can be * @return a random {@link Integer} within the supplied minumum and maximum * range. */ public static Integer aRandomInteger(final int min, final int max) { if (min == max) { return min; } else { return min + Integer.valueOf(nextInt(max - min)); } } /** * Build a random {@link Short}. For example *

* * Short aRandomAge = RandomBuilder.aRandomShort(); * . * * @return a random {@link Short}. */ public static Short aRandomShort() { return Short.valueOf((short) nextInt(Short.MAX_VALUE)); } /** * Build a random {@link Short} within the supplied minumum and maximum * range. For example *

* * Short aRandomAge = RandomBuilder.aRandomShort(1,100); * * * @param min * the minimum value can be * @param max * the maximum value can be * @return a random {@link Short} within the supplied minumum and maximum * range. */ public static Short aRandomShort(final short min, final short max) { if (min == max) { return min; } else { return Short.valueOf((short) (min + nextInt(max - min))); } } /** * Build a random {@link Long}. For example *

* * Long aRandomAge = RandomBuilder.aRandomLong(1,100); * * * @return a random {@link Long}. */ public static Long aRandomLong() { return Long.valueOf(nextLong()); } /** * Build a random {@link Long} within the supplied minumum and maximum * range. For example *

* * Long aRandomAge = RandomBuilder.aRandomLong(1,100L); * * * @param min * the minimum value can be * @param max * the maximum value can be * @return a random {@link Long} within the supplied minumum and maximum * range. */ public static Long aRandomLong(final int min, final int max) { if (min == max) { return (long) min; } else { return Long.valueOf(min + nextInt(max - min)); } } /** * Build a random {@link Double}. For example *

* * Double aRandomHeight = RandomBuilder.aRandomDouble(); * * * @return a random {@link Double}. */ public static Double aRandomDouble() { return Double.valueOf(nextDouble()); } /** * Build a random {@link Float}. For example *

* * Float aRandomHeight = RandomBuilder.aRandomFloat(); * * * @return a random {@link Float}. */ public static Float aRandomFloat() { return Float.valueOf(nextFloat()); } /** * Return one of the specified range of values. For exampl *

* * String aRandomName = RandomBuilder.oneOf("Bob", "Alice", "Jane"); * * * @param * the type of the value * @param rangeOfValues * the range of values to pick a value from * @return one of supplied arguments */ @SuppressWarnings("unchecked") public static T oneOf(final T... rangeOfValues) { return rangeOfValues == null ? null : rangeOfValues[nextInt(rangeOfValues.length)]; } /** * Build a random {@link Boolean}. For example *

* * Boolean aRandomHasSibilings = RandomBuilder.aRandomBoolean(); * * * @return a random {@link Boolean}. */ public static Boolean aRandomBoolean() { return Boolean.valueOf(nextBoolean()); } /** * Build a random {@link Date} with an year either side of today. For * example *

* * Date aRandomBirthday = RandomBuilder.aRandomDate(); * * * @return a random {@link Date} with an year either side of today. */ public static Date aRandomDate() { return addSeconds(new Date(), nextInt(SECONDS_IN_A_YEAR)); } /** * Build a random {@link LocalDate} with an year either side of today. For * example *

* * LocalDate aRandomBirthday = RandomBuilder.aRandomLocalDate(); * * * @return a random {@link LocalDate} with an year either side of today. */ public static LocalDate aRandomLocalDate() { return LocalDate.now().plus(nextInt(DAYS_PER_YEAR), ChronoUnit.DAYS); } /** * Build a random {@link LocalDateTime} with an year either side of today. * For example *

* * LocalDateTime aRandomBirthday = RandomBuilder.aRandomLocalDateTime(); * * * @return a random {@link LocalDateTime} with an year either side of today. */ public static LocalDateTime aRandomLocalDateTime() { return LocalDateTime.now().plus(nextInt(SECONDS_IN_A_YEAR), ChronoUnit.SECONDS); } /** * Build a random {@link ZonedDateTime} with an year either side of today. * For example *

* * ZonedDateTime aRandomBirthday = RandomBuilder.aRandomZonedDateTime(); * * * @return a random {@link ZonedDateTime} with an year either side of today. */ public static ZonedDateTime aRandomZonedDateTime() { return ZonedDateTime.now().plus(nextInt(SECONDS_IN_A_YEAR), ChronoUnit.SECONDS); } /** * Build a random {@link ZonedDateTime} with an year either side of today. * For example *

* * ZonedDateTime aRandomBirthday = RandomBuilder.aRandomZonedDateTime(); * * * @return a random {@link ZonedDateTime} with an year either side of today. */ public static Instant aRandomInstant() { return Instant.now().plus(nextInt(SECONDS_IN_A_YEAR), ChronoUnit.SECONDS); } /** * Build a random {@link BigDecimal}. For example *

* * BigDecimal aRandomWeight = RandomBuilder.aRandomDecimal(); * * * @return a random {@link BigDecimal}. */ public static BigDecimal aRandomDecimal() { return BigDecimal.valueOf(nextInt()).round(new MathContext(10, RoundingMode.HALF_UP)).movePointLeft(nextInt(5)); } /** * Build a random {@link Byte}. For example *

* * BigDecimal aRandomByte = RandomBuilder.aRandomByte(); * * * @return a random {@link Byte}. */ public static Byte aRandomByte() { return (byte) nextInt(Byte.MAX_VALUE); } /** * Build a random array of bytes. For example *

* * byte [] aRandomID = RandomBuilder.aRandomByteArray(); * * * @return a random array of bytes */ public static byte[] aRandomByteArray() { byte[] array = new byte[aRandomInteger(2, 1000)]; for (int i = 0; i < array.length; ++i) { array[i] = aRandomByte(); } return array; } /** * Build a random {@link Character}. For example *

* * Character aRandomInitial = RandomBuilder.aRandomCharacter(); * * * @return a random {@link Character}. */ public static Character aRandomChar() { return randomAlphabetic(1).charAt(0); } /** * Build a random instance of the supplied enumeration. For example *

* * Gender aRandomGender = RandomBuilder.aRandomEnum(Gender.class); * * * @param enumType * the enumeration to create a random instance of * @return a random instance of the supplied enumeration. */ public static > E aRandomEnum(final Class enumType) { E[] enumerationValues = enumType.getEnumConstants(); if (enumerationValues.length == 0) { throw new RandomBuilderException("Enumeration " + enumType.getName() + "has no values"); } else { return enumerationValues[nextInt(enumerationValues.length)]; } } /** * Build an array of random values from the supplied enumeration. For * example *

* * EyeColour [] eyeColours = RandomBuilder.aRandomArrayOfEnum(EyeColour.class); * * * @param enumType * the enumeration to create an array of * @return an array of random values from the supplied enumeration. */ public static > E[] aRandomArrayOfEnum(final Class enumType) { return aRandomArrayOfEnum(enumType, DEFAULT_MIN_ARRAY_SIZE, DEFAULT_MAX_ARRAY_SIZE); } /** * Build an array of random values from the supplied enumeration of a given * size. For example *

* * EyeColour [] eyeColours = RandomBuilder.aRandomArrayOfEnum(EyeColour.class, 2, 5); * * * @param enumType * the enumeration to create an array of * @param min * the minimum size the array can be * @param max * the maxiumum size the array can be * @return an array of random values from the supplied enumeration. */ public static > E[] aRandomArrayOfEnum(final Class enumType, final int min, final int max) { return ValueFactories.aRandomArrayOf(ValueFactories.aRandomEnum(enumType)).createValue( enumType, aRandomInteger(min, max)); } /** * Build an array of randomly populated instances of the supplied type. For * example *

* * Person [] aRandomCrowd = RandomBuilder.aRandomArrayOf(Person.class); * * * @param type * the type to create an array of * @return an array of randomly populated instances of the supplied type */ public static T[] aRandomArrayOf(final Class type) { return aRandomArrayOf(type, DEFAULT_MIN_ARRAY_SIZE, DEFAULT_MAX_ARRAY_SIZE); } /** * Build an array of randomly populated instances of the supplied type if a * given size. For example *

* * Person [] aRandomCrowd = RandomBuilder.aRandomArrayOf(Person.class,10,50); * * * @param type * the type to create an array of * @param min * the minimum size the array can be * @param max * the maxiumum size the array can be * @return an array of randomly populated instances of the supplied type */ public static T[] aRandomArrayOf(final Class type, final int min, final int max) { return ValueFactories.aRandomArrayOf(instanceFactoryFor(type)).createValue(type, aRandomInteger(min, max)); } /** * Build a collection of randomly populated instances of the supplied type. * For example *

* * Collection aRandomCrowd = RandomBuilder.aRandomCollectionOf(Person.class); * * * @param type * the type to create a collection of * @return a collection of randomly populated instances of the supplied type */ public static Collection aRandomCollectionOf(final Class type) { return aRandomCollectionOf(type, DEFAULT_MIN_ARRAY_SIZE, DEFAULT_MAX_ARRAY_SIZE); } /** * Build a collection of randomly populated instances of the supplied type * if a given size. For example *

* * Collection aRandomCrowd = RandomBuilder.aRandomCollectionOf(Person.class,10,50); * * * @param type * the type to create a collection of * @param min * the minimum size the collection can be * @param max * the maxiumum size the collection can be * @return a collection of randomly populated instances of the supplied type * if a given size */ public static Collection aRandomCollectionOf(final Class type, final int min, final int max) { return aRandomListOf(type, min, max); } /** * Build a list of randomly populated instances of the supplied type. For * example *

* * List aRandomCrowd = RandomBuilder.aRandomListOf(Person.class); * * * @param type * the type to create a list of * @return a list of randomly populated instances of the supplied type */ public static List aRandomListOf(final Class type) { return aRandomListOf(type, DEFAULT_MIN_ARRAY_SIZE, DEFAULT_MAX_ARRAY_SIZE); } /** * Build a random list of randomly populated instances of the supplied type * if a given size. For example *

* * List aRandomCrowd = RandomBuilder.aRandomListOf(Person.class); * * * @param type * the type to create a random list of * @param min * the minimum size the list can be * @param max * the maxiumum size the list can be * @return a random list of randomly populated instances of the supplied * type */ public static List aRandomListOf(final Class type, final int min, final int max) { return Arrays.asList(aRandomArrayOf(type, min, max)); } /** * Build a random instance of the supplied type. For example *

* * Person aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class); * *

* * @param type * the type to create a random instance of * @param restrictions * an array of restrictions which control how the random instance * is built * @return a random instance of the supplied type */ public static T aRandomInstanceOf(final Class type) { return aRandomInstanceOf(type, new RandomRestriction[0]); } /** * Build a random instance of the supplied type. An array of restrictions * can be supplied as arguments if control is required over how some of the * properties are populated. For example *

* * Person aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class); * *

* For examples on how to use restrictions to define the random object * See:

* *
	 * {@link RandomBuilder#path(String, Object)}
	 * {@link RandomBuilder#property(String, Object)}
	 * {@link RandomBuilder#excludePath(String)}
	 * {@link RandomBuilder#excludeProperty(String)}
	 * {@link RandomBuilder#subtype(Class, Class)}
	 * {@link RandomBuilder#subtype(Class, Class...)}
	 * {@link RandomBuilder#collectionSize(int)}
	 * {@link RandomBuilder#collectionSize(int, int)}
	 * {@link RandomBuilder#collectionSizeForPath(String, int)}
	 * {@link RandomBuilder#collectionSizeForProperty(String, int)}
	 * {@link RandomBuilder#collectionSizeForProperty(String, int, int)}
	 * 
* * @param type * the type to create a random instance of * @param restrictions * an array of restrictions which control how the random instance * is built * @return a random instance of the supplied type */ public static T aRandomInstanceOf(final Class type, final RandomRestriction... restrictions) { try { return instanceFactoryFor(type, restrictions).createValue(); } catch (BeanBuilderException e) { throw new RandomBuilderException("Failed to create a random instance of " + type.getName(), e); } catch (ValueFactoryException e) { throw new RandomBuilderException("Failed to create a random instance of " + type.getName(), e); } } /** * Build a random instance of the supplied type. A list of restrictions can * be supplied as arguments if control is required over how some of the * properties are populated. For example *

* * List restrictions = new ArrayList();
* restrictions.add(RandomBuilder.path("person.surname","Smith"));
* restrictions.add(RandomBuilder.property("age",25));
* Person aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class, restrictions); *
*

* For examples on how to use restrictions to define the random object * See:

* *
	 * {@link RandomBuilder#path(String, Object)}
	 * {@link RandomBuilder#property(String, Object)}
	 * {@link RandomBuilder#excludePath(String)}
	 * {@link RandomBuilder#excludeProperty(String)}
	 * {@link RandomBuilder#subtype(Class, Class)}
	 * {@link RandomBuilder#subtype(Class, Class...)}
	 * {@link RandomBuilder#collectionSize(int)}
	 * {@link RandomBuilder#collectionSize(int, int)}
	 * {@link RandomBuilder#collectionSizeForPath(String, int)}
	 * {@link RandomBuilder#collectionSizeForProperty(String, int)}
	 * {@link RandomBuilder#collectionSizeForProperty(String, int, int)}
	 * 
* * @param type * the type to create a random instance of * @param restrictions * an array of restrictions which control how the random instance * is built * @return a random instance of the supplied type */ public static T aRandomInstanceOf(final Class type, final List restrictions) { return instanceFactoryFor(type, restrictions.toArray(new RandomRestriction[0])).createValue(); } /** * Build and instance of a {@link RandomRestriction} which assigns the value * to the specific property. For example *

* * Person aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class, RandomBuilder.property("surname", "Smith")); * * * @param property * the property to assign e.g. "name" * @param value * the value to assign the property e.g. "Jane Doe" */ public static RandomRestriction property(final String property, final Object value) { return (builder) -> builder.property(property, value); } /** * Build and instance of a {@link RandomRestriction} which assigns an * {@link ValueFactory} derived value to the specific property. For example *

* * Person aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class, RandomBuilder.property("surname", ValueFactories.oneOf("Smith","Brown")); * * * @param property * the property to assign * @param value * the value to assign the property */ public static RandomRestriction property(final String property, final ValueFactory factory) { return (builder) -> builder.property(property, factory); } /** * Build and instance of a {@link RandomRestriction} which uses the * {@link ValueFactory} to create instances of the specified type. For * example *

* * Shape aRandomPerson = RandomBuilder.aRandomInstanceOf(Person.class, RandomBuilder.factory(Email.class, new EmailFactory()); * * * @param type * the type to use the instance factory for * @param factory * the instance factory to use */ public static RandomRestriction factory(final Class type, final ValueFactory factory) { return (builder) -> builder.factory(type, factory); } /** * Build and instance of a {@link RandomRestriction} which will prevent the * property being assigned any value * * @param property * the path to assign e.g. "name" */ public static RandomRestriction excludeProperty(final String property) { return (builder) -> builder.excludeProperty(property); } /** * Build and instance of a {@link RandomRestriction} which assigns the value * to the specific path * * @param path * the path to assign e.g. "person.name" * @param value * the value to assign the path e.g. "Jane Doe" */ public static RandomRestriction path(final String path, final Object value) { return (builder) -> builder.path(path, value); } /** * Build and instance of a {@link RandomRestriction} which assigns an * {@link ValueFactory} derived value to the specific path * * @param path * the path to assign e.g. "person.name" * @param value * the value to assign the path */ public static RandomRestriction path(final String path, final ValueFactory factory) { return (builder) -> builder.path(path, factory); } /** * Build and instance of a {@link RandomRestriction} which will prevent the * value at the path being assigned any value * * @param path * the path to assign e.g. "person.name" */ public static RandomRestriction excludePath(final String path) { return (builder) -> builder.excludePath(path); } /** * Build and instance of a {@link RandomRestriction} which will use the * given subtype of a super type when instantiating the subtype. * * @param superType * the super type * @param subType * the sub type to use when creating an instance of the super * type */ public static

RandomRestriction subtype(final Class

superType, final Class subType) { return (builder) -> builder.subtype(superType, subType); } /** * Build and instance of a {@link RandomRestriction} which will use any of * the given sub types of a super type when instantiating the super type. * * @param superType * the super type * @param subType * the sub types to use when creating an instance of the super * type */ @SuppressWarnings("unchecked") public static

RandomRestriction subtype(final Class

superType, final Class... subTypes) { return (builder) -> builder.subtype(superType, subTypes); } /** * Build and instance of a {@link RandomRestriction} which will limit the * size of all collections to the specified size * * @param size * the size of the collection */ public static

RandomRestriction collectionSize(final int size) { return (builder) -> builder.collectionSizeOf(size); } /** * Build and instance of a {@link RandomRestriction} which will limit the * size of all collections to within the specified range * * @param min * the minimum size the collections can be * @param max * the maximum size the collections can be */ public static

RandomRestriction collectionSize(final int min, final int max) { return (builder) -> builder.collectionSizeRangeOf(min, max); } /** * Build and instance of a {@link RandomRestriction} which will set the size * of the collection at the specified path * * @param path * the path to assign the collection size of e.g. * "person.siblings" * @param size * the size of the collection */ public static

RandomRestriction collectionSizeForPath(final String path, final int size) { return (builder) -> builder.collectionSizeForPathOf(path, size); } /** * Build and instance of a {@link RandomRestriction} which will limit the * size of the collection at the specifed path * * @param min * the minimum size the collections can be * @param max * the maximum size the collections can be */ public static

RandomRestriction collectionSizeForPath(final String path, final int min, final int max) { return (builder) -> builder.collectionSizeRangeForPathOf(path, min, max); } /** * Build and instance of a {@link RandomRestriction} which will set the size * of the collection at the specified property * * @param property * the property to assign the collection size of e.g. * "person.siblings" * @param size * the size of the collection */ public static

RandomRestriction collectionSizeForProperty(final String property, final int size) { return (builder) -> builder.collectionSizeForPropertyOf(property, size); } /** * Build and instance of a {@link RandomRestriction} which will limit the * size of the collection at the specifed property * * @param min * the minimum size the collections can be * @param max * the maximum size the collections can be */ public static

RandomRestriction collectionSizeForProperty(final String property, final int min, final int max) { return (builder) -> builder.collectionSizeRangeForPropertyOf(property, min, max); } @SuppressWarnings("unchecked") private static ValueFactory instanceFactoryFor(final Class type, final RandomRestriction... restrictions) { ValueFactory factory = RANDOM_FACTORIES.get(type); if (factory == null) { BeanBuilder builder = BeanBuilder.aRandomInstanceOf(type); for (RandomRestriction restriction : restrictions) { restriction.applyTo(builder); } factory = ValueFactories.theValue(builder.build()); } return factory; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy