dummymaker

DummyMaker

Minimum required Java version GitHub Action Quality Gate Status Coverage Maintainability Rating Lines of Code

DummyMaker is a library that generates random Java Classes / Records / Sealed Interfaces / Sealed Classes for you.

Library can even do simple export in CSV/JSON/XML/SQL formats.

Library have no dependencies.

Dependency :rocket:

Gradle

implementation "com.github.goodforgod:dummymaker:4.0.0"

Maven

<dependency>
    <groupId>com.github.goodforgod</groupId>
    <artifactId>dummymaker</artifactId>
    <version>4.0.0</version>
</dependency>

Content

When to use?

There are plenty of use cases where DummyMaker is useful:

Simple example on how you would create class with random data using constructor manually:

Street street = new Street(12, 1, "Revolution Sq");
Address address = new Address(street, "123456", "Saint-Petersburg");
Person person = new Person("Foo", "Bar", "foo.bar@ya.ru", address);

And if classes do not provide constructors with parameters:

Street street = new Street();
street.setNumber(12);
street.setType(1);
street.setName("Revolution Sq");

Address address = new Address();
address.setStreet(street);
address.setZipCode("123456");
address.setCity("Saint-Petersburg");

Person person = new Person();
person.setFirstName("Foo");
person.setLastName("Bar");
person.setEmail("foo.bar@ya.ru");
person.setAddress(address);

Using DummyMaker library, it is easy to generate Person class with all inner classes with random data for all fields:

GenFactory factory = GenFactory.build();
Person person = factory.build(Person.class);

Factory Examples

GenFactory provides different methods for random class generation.

Given such Java Class as a model:

class User {

  public String name;
  public String surname;
}

Example on how to generate single random Java Class with random field values:

GenFactory factory = GenFactory.build();
User user = factory.build(User.class);

Example on how to generate standard Java Class (can be used with most of the standard Java Classes):

GenFactory factory = GenFactory.build();
Integer integer = factory.build(Integer.class);

Example how to generate list of Java Classes:

GenFactory factory = GenFactory.build();
List<User> users = factory.build(User.class, 1000);

Example how to generate stream of Java Classes:

GenFactory factory = GenFactory.build();
factory.stream(User.class, 1000)
        .forEach(System.out::println);

In case have complex constructor, or it is required to generate on instantiated class, you can provide Supplier for factory:

GenFactory factory = GenFactory.build();
User user = factory.build(() -> new User());

Configuration

GenFactory Builder provides different methods to configure random class generation and generated data specifications.

Example how to configure GenFactory, check its Builder for more settings:

class Account {
    
  public String type = "simple";
  public String name;
}

GenFactory factory = GenFactory.builder()
        .overrideDefaultValues(false)
        .applyCase(NamingCases.UPPER_CASE)
        .build();

Account account = factory.build(Account.class);

Available configurations:

GenRules

GenFactory allows to provide rules for configuring class generation for specific fields.

Rules can be used to configure specific generators for specific fields or exclude fields.

GenRule examples will be based on this class:

class Account {

  public Integer number;
  public String type;
  public String name;
}

Example on how to generate specific random value for any field:

List<String> values = Arrays.asList("1", "5", "9");

GenFactory factory = GenFactory.builder()
        .addRule(GenRule.ofClass(Account.class)
                .generateForNames("type", () -> CollectionUtils.random(values)))
        .build();

Account account = factory.build(Account.class);

Class

Class specific Rule is applied only for specific Class.

Example how to add specific Generator for fields by their names:

GenFactory factory = GenFactory.builder()
        .addRule(GenRule.ofClass(Account.class)
                .generateForNames("type", "name", () -> new NameGenerator()))
        .build();

Account account = factory.build(Account.class);

Global

Global Rule is applied for all Classes.

Example how to add specific Generator for all types:

GenFactory factory = GenFactory.builder()
        .addRule(GenRule.ofGlobal()
                .generateForTypes(String.class, () -> new NameGenerator()))
        .build();

Account account = factory.build(Account.class);

GenAnnotation Examples

Library provides lots of annotations to mark out class for random value generation.

This is an alternative to GenRules mechanism for random value generation configuring.

Check io.dummymaker.annotation package for all of them.

Standard

Using annotations like @GenEmail, @GenId, @GenName, etc., it allows mark out which Generator to use for which field.

class Account {

  @GenId
  private String id;
  @GenName
  private String name;
  @GenInt(from = 1, to = 10)
  private long number;
  @GenAddress
  private String address;
  @GenEmail
  private String email;
}

GenFactory factory = GenFactory.build();
Account account = factory.build(Account.class);

Special

Library provides annotations that allow to provide special behavior when generating random values of typically used for complex values generation:

Configuration annotations:

@GenAuto
@GenDepth(2)
class Account {

  @GenSequence
  private Long id;
  @GenTime
  private String timestamp;
  @GenUnixTime
  private long unixTime;
  @GenIgnore
  private String ignored;
  @GenList
  private List<String> emails;
  @GenSet(generator = TypeGenerator.class)
  private Set<String> types;
  @GenMap
  private Map<Integer, String> numbers;
  
  private Account boss;
}

GenFactory factory = GenFactory.build();
Account account = factory.build(Account.class);

GenAnnotations

Library provides lots of GenAnnotations:

String Annotations ``` @GenAddress @GenAddressFull @GenBtcAddress @GenBtcTxHash @GenCadastral @GenCategory @GenCity @GenCompany @GenCountry @GenCurrency @GenDescription @GenDistrict @GenEmail @GenEthAddress @GenEthTxHash @GenFrequency @GenFullname @GenGender @GenHexData @GenHexNumber @GenHouse @GenId @GenIdBig @GenIPv4 @GenIPv6 @GenJob @GenJson @GenLevel @GenLogin @GenMcc @GenMerchant @GenMiddleName @GenName @GenNickname @GenNoun @GenPass @GenPassword @GenPhone @GenPhoto @GenProduct @GenRole @GenStatus @GenStreet @GenString @GenStringValues @GenSurname @GenTag @GenVersion ```
Number Annotations ``` @GenBigDecimal @GenBigInteger @GenByte @GenChar @GenCharacter @GenDouble @GenDoubleSmall @GenFloat @GenFloatSmall @GenInt @GenLong @GenMcc @GenPostal @GenPrice @GenSequence @GenShort ```
Time Annotations ``` @GenCalendar @GenDate @GenDateSql @GenDayOfWeek @GenDuration @GenInstant @GenLocalDate @GenLocalDateTime @GenLocalTime @GenMonth @GenMonthDay @GenOffsetDateTime @GenOffsetTime @GenPeriod @GenTimeSql @GenTimestamp @GenYear @GenYearMonth @GenZonedDateTime @GenZonedOffset ```
Other Annotations ``` @GenBoolean @GenNull @GenUri @GenUrl @GenUuid ```
Parameterized Generators ``` @GenArray @GenArray2D @GenEnum @GenList @GenMap @GenSet @GenTime @GenUnixTime ```

Generators

Library provides lots of generators:

String Generators ``` AddressFullGenerator.java AddressGenerator.java BtcAddressGenerator.java BtcTxHashGenerator.java CadastralGenerator.java CategoryGenerator.java CityGenerator.java CompanyGenerator.java CountryGenerator.java CurrencyGenerator.java DescriptionGenerator.java DistrictGenerator.java DocumentGenerator.java EmailGenerator.java EthAddressGenerator.java EthTxHashGenerator.java ExtensionGenerator.java FileGenerator.java FormatGenerator.java FrequencyGenerator.java FullnameGenerator.java GenderGenerator.java HexDataGenerator.java HexNumberGenerator.java HouseGenerator.java IdBigGenerator.java IdGenerator.java IPv4Generator.java IPv6Generator.java JobGenerator.java JsonGenerator.java LevelGenerator.java LoginGenerator.java MccGenerator.java MerchantGenerator.java MiddleNameGenerator.java NameGenerator.java NounGenerator.java PasswordGenerator.java PhoneGenerator.java PhotoGenerator.java ProductGenerator.java RoleGenerator.java StatusGenerator.java StreetGenerator.java StringGenerator.java StringValuesGenerator.java SurnameGenerator.java TagGenerator.java TypeGenerator.java VersionGenerator.java ```
Number Generators ``` BigDecimalGenerator.java BigIntegerGenerator.java ByteGenerator.java CharacterGenerator.java CharGenerator.java DoubleGenerator.java DoubleSmallGenerator.java FloatGenerator.java FloatSmallGenerator.java IntegerGenerator.java IntegerSmallGenerator.java LongGenerator.java MccGenerator.java PostalGenerator.java PriceGenerator.java SequenceGenerator.java ShortGenerator.java UnixTimeGenerator.java ```
Time Generators ``` CalendarGenerator.java DateGenerator.java DateSqlGenerator.java DayOfWeekGenerator.java DurationGenerator.java InstantGenerator.java LocalDateGenerator.java LocalDateTimeGenerator.java LocalTimeGenerator.java MonthDayGenerator.java MonthGenerator.java OffsetDateTimeGenerator.java OffsetTimeGenerator.java PeriodGenerator.java TimeSqlGenerator.java TimestampGenerator.java YearGenerator.java YearMonthGenerator.java ZonedDateTimeGenerator.java ZonedOffsetGenerator.java ```
Other Generators ``` BooleanGenerator.java EmbeddedGenerator.java NullGenerator.java ObjectGenerator.java UriGenerator.java UrlGenerator.java UuidGenerator.java ```
Parameterized Annotations ``` Array2DParameterizedGenerator.java ArrayParameterizedGenerator.java EnumParameterizedGenerator.java ListParameterizedGenerator.java MapParameterizedGenerator.java SetParameterizedGenerator.java TimeParameterizedGenerator.java ```

Export

Library provides simple Exporter classes to export objects in CSV, JSON, XML and even SQL formats.

Each Exporter provides different methods to export single Java class, list of classes or stream of classes.

Exporter have different configurations, like naming case for field names, also custom Writer can be supplied for file writing.

Examples will be based on this class:

class Account {

  public Integer number;
  public String type;
  public String name;
}

Annotations

Library provides special export annotations:

JSON

JsonExporter can export Java classes in JSON format.

Example:

GenFactory factory = GenFactory.build();
List<Account> accounts = factory.build(Account.class, 2);

Exporter exporter = JsonExporter.build();
String json = exporter.exportAsString(accounts);

Result:

[
  {"number":1657591124,"type":"invalid","name":"Palmer"},
  {"number":1243742023,"type":"rejected","name":"Cindy"}
]

CSV

CsvExporter can export Java classes in CSV format.

Example:

GenFactory factory = GenFactory.build();
List<Account> accounts = factory.build(Account.class, 2);

Exporter exporter = CsvExporter.build();
String csv = exporter.exportAsString(accounts);

Result:

number,type,name
1032136236,rejected,Mike
338683126,failed,Jesus

XML

XmlExporter can export Java classes in XML format.

Example:

GenFactory factory = GenFactory.build();
List<Account> accounts = factory.build(Account.class, 2);

Exporter exporter = XmlExporter.build();
String xml = exporter.exportAsString(accounts);

Result:

<AccountList>
    <Account>
        <number>189092582</number>
        <type>invalid</type>
        <name>Antonio</name>
    </Account>
    <Account>
        <number>58523878</number>
        <type>failed</type>
        <name>Carlos</name>
    </Account>
</AccountList>

SQL

SqlExporter can export Java classes in SQL format.

This is useful when you need to insert millions rows into SQL database, such insert query is one of the fastest ways.

Example:

GenFactory factory = GenFactory.build();
List<Account> accounts = factory.build(Account.class, 2);

Exporter exporter = SqlExporter.build();
String sql = exporter.exportAsString(accounts);

Result:

CREATE TABLE IF NOT EXISTS account(
	number	INT,
	type	VARCHAR,
	name	VARCHAR,
	PRIMARY KEY (number)
);

INSERT INTO account(number, type, name) VALUES
(1682341022, 'failed', 'Megan'),
(2052081057, 'invalid', 'Tina');

Writer

When exporting to file, you can provide your own Writer implementation.

Example:

GenFactory factory = GenFactory.build();
List<Account> accounts = factory.build(Account.class, 2);

Exporter exporter = JsonExporter.builder().withWriter(name -> new SimpleFileWriter(false, name)).build();
exporter.exportAsFile(accounts);

Customization Examples

Library allows easily create custom Generator or annotations.

Simple Generator

Simple Generator that produce some random value.

Generator can specify pattern that will be used choose where to apply such Generator based on field name.

public class IntegerMyGenerator implements Generator<Integer> {

    private final Pattern pattern = Pattern.compile("age|grade|group", CASE_INSENSITIVE);

    @Override
    public Pattern pattern() {
        return pattern;
    }

    @Override
    public Integer generate() {
        return ThreadLocalRandom.current().nextInt(1, 101);
    }
}

Parameterized Generator

Generator sometimes require more context to use for random value generation, than it is possible to implement ParameterizedGenerator.

public final class MyParameterizedGenerator implements ParameterizedGenerator<String> {

    @Override
    public String get(@NotNull GenParameters parameters) {
        return parameters.namingCase().apply("myValue");
    }

    @Override
    public String get() {
        return "myValue";
    }
}

Custom Annotation

You can apply custom Generator not only using GenRules but also using @GenCustom annotation.

@GenCustom annotation require Generator

class Account {

  @GenCustom(IntegerMyGenerator.class)
  public String type;
}

Custom Annotation Factory

AnnotationGeneratorFactory is used when you need to instantiate generate with arguments from annotation.

AnnotationGeneratorFactory must have zero argument constructor.

@GenCustomFactory is used to indicate which factory for which annotation to use.

Given annotation:

@GenCustomFactory(CustomIntegerAnnotationGeneratorFactory.class)
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface GenIntCustom {

    @Range(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE)
    int from() default 0;

    @Range(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE)
    int to() default Integer.MAX_VALUE;
}

Respected AnnotationGeneratorFactory should look like:

public final class IntegerAnnotationGeneratorFactory implements CustomIntegerAnnotationGeneratorFactory<GenIntCustom> {

    @Override
    public @NotNull Generator<Integer> get(GenIntCustom annotation) {
        return new IntegerGenerator(annotation.from(), annotation.to());
    }
}

Previous Versions

Documentation for versions 3.X.X in this document.

Documentation for versions 1.X.X in this document.

License

This project licensed under the MIT - see the LICENSE file for details.