Library can generate Data Objects filled random data for your tests, database setup, Big Data setups or other workloads. Library is very flexible at tuning.
Library can even do simple export in CSV/JSON/XML/SQL formats.
Documentation for versions 1.X.X in this document.
Gradle
implementation "com.github.goodforgod:dummymaker:3.3.1"
Maven
<dependency>
<groupId>com.github.goodforgod</groupId>
<artifactId>dummymaker</artifactId>
<version>3.3.1</version>
</dependency>
Example how to produce 1001 Users in no time.
All user data is automatically generated and proper generators are selected due to @GenAuto annotation.
Class that is instantiated by factory via build method must have zero argument constructor (Can be private).
@GenAuto
public class User {
/**
* All fields will have unique data after being processed by factory
*/
private int number;
private String name;
private String surname;
private List<User> relatives;
}
public static List<User> getUsers() {
final GenFactory factory = new GenFactory();
User user = factory.build(User.class);
// All users have unique data in their fields
List<User> users = factory.build(User.class, 1000);
return users;
}
Factory not only instantiate classes but also provides other contracts to manipulate with objects like using supplier.
final GenFactory factory = new GenFactory();
Set<User> users = factory.stream(() -> new User(), 1)
.collect(Collectors.toSet());
User user = new User();
User filled = factory.fill(user);
There are more other contracts available just check GenFactory.
Also, factory can export huge amount of data in one attempt when data cannot be proceeded inmemory via export contract.
In such case export that is provided should append file with each export execution. Default IWriter doesn’t do that by default, so such option should be activated.
final GenFactory factory = new GenFactory();
final JsonExporter exporter = new JsonExporter(fileName -> new FileWriter(fileName, false)); // do not delete file before write
factory.export(User.class, 100_000_000_000L, exporter);
@GenAuto annotation provides depth field that is required for embedded fields such as relatives in this example.
For such class, each User will have field relatives filled with data up to level 3 in depth. Because each User will have other users as its data and such data can be represented as a tree. So leaf that has its depth of 3 from root will be the last who have field relatives filled with data.
Maximum depth allowed is 20 (Check @GenAuto.MAX parameter).
@GenAuto(depth = 3)
public class User {
private int number;
private String name;
private String surname;
private List<User> relatives;
}
In case you have no intention or opportunity to annotate class even with @GenAuto annotation, you can configure all generators and fields you want to fill or ignore with factory GenRules configuration.
In case you want to fill only specific field to be filled with data you can configure such behavior via GenRule for specific class.
GenRule rule = GenRule.of(User.class)
.add(NameGenerator.class, "name")
.add(ShortGenerator.class, int.class);
GenFactory factory = new GenFactory(rule);
User user = factory.build(User.class);
In this case only name and number fields will be filled with data, as they are the only one specified per GenRule configuration.
In case you want factory automatically fill fields based on their types and names, you can setup auto (same as GenAuto annotation).
Second argument specifies depth of complex objects generation, check this section for more info.
GenRule rule = GenRule.auto(User.class, 2)
.add(NameGenerator.class, "name")
.add(ShortGenerator.class, int.class);
GenFactory factory = new GenFactory(rule);
User user = factory.build(User.class);
In this case fields name and number will be filled as previously but also all other fields will be automatically filled.
GenRule rule = GenRule.auto(User.class, 2);
GenFactory factory = new GenFactory(rule);
User user = factory.build(User.class);
This will have same affect as previous , due to fields name and number been automatically filled.
In case you have a lot of common fields with same values in different classes you can setup global for all classes that will be filled.
GenRule rule = GenRule.global(2)
.add(NameGenerator.class, "name")
.add(ShortGenerator.class, int.class);
GenFactory factory = new GenFactory(rule);
User user = factory.build(User.class);
In this case all fields with name name in all classes will be filled using NameGenerator and same for int fields with ShortGenerator.
You can add anonymous generator or lambda generator as run for your GenRules configuration.
final IGenerator<String> generator = () -> ThreadLocalRandom.current().nextBoolean()
? "Bob"
: "Bill";
GenRule rule = GenRule.auto(User.class, 1)
.add(generator, "name");
GenFactory factory = new GenFactory(rule);
User user = factory.build(User.class);
There are a lot of generators available such as IntegerGenerator, LongGenerator, CityGenerator, etc.
All generators can be found in package io.dummymaker.generator.
As well as all annotations such as GenInteger, GenLong, GenCity, etc. can be found in package io.dummymaker.annotation.simple.
Responsible for filling array data, can be applied as annotation or GenRule. Will be used automatically via @GenAuto or auto GenRule.
public class User {
@GenArray
private int[] numbers;
@GenArray
private int[][] numberArrays;
}
Responsible for filling collection data, can be applied as annotation or GenRule. Will be used automatically via @GenAuto or auto GenRule.
public class User {
@GenList
private List<Integer> numberList;
@GenSet
private Set<Integer> numberSet;
@GenMap
private Map<Integer, String> numberMap;
}
Responsible for filling time data, can be applied as annotation or GenRule. Will be used automatically via @GenAuto or auto GenRule.
GenTime annotation is used to create time/dateTime/timestamps for field. Automatically identify field time type and generate value for it.
Supported time fields types:
public class User {
@GenTime
private Timestamp timestamp;
@GenTime
private LocalDateTime dateTime;
}
You cas specify formatter to export dates \ times.
public class User {
@GenTime(formatter = "HH:mm")
private LocalTime localTime;
@GenTime(formatter = "yyyy-MM HH:mm")
private LocalDateTime dateTime;
}
You can export dates \ times as unix time format.
public class User {
@GenTime(exportAsUnixTime = true)
private Timestamp timestamp;
@GenTime(exportAsUnixTime = true)
private LocalDateTime dateTime;
}
Responsible for filling complex data, can be applied as annotation or GenRule. Will be used automatically via @GenAuto or auto GenRule.
public class User {
@GenEmbedded
private User parent;
}
GenExportForce allow to force export object field, even if it is not generated by GenAnnotation.
GenExportIgnore allow to ignore object’s field during export.
GenExportRename allow to rename Dummy export field name or Class Name (Annotate constructor to rename class export name).
GenIgnore field will not be filled with value when generated.
GenEnum generates Enum field value.
GenSequence annotation with option (from) used to numerate Dummies fields as sequence (Works on Integer/Long/String field types).
GenCustom used to mark field with custom generators.
Information about different exporters can be found here.
You can extend basic functionality with your own annotations and generators. All infrastructure will support custom generators, annotations, generate factories with no doubt.
You need to:
Simple generator that produce specific value.
Generator can have pattern to register it for @GenAuto discovery.
public class IntegerSmallGenerator implements IGenerator<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);
}
}
Is used to build complex values for fields, when simple IGenerator implementation is insufficient, Gen annotation require special parameters or when you need to access field.
public class CustomComplexGenerator implements IComplexGenerator {
@Override
public Object generate(Annotation annotation, Field field, IGenStorage storage, int depth) {
final int from = GenInteger.class.equals(annotation.annotationType())
? ((GenInteger) annotation).from()
: 0;
final int to = GenInteger.class.equals(annotation.annotationType())
? ((GenInteger) annotation).to()
: Integer.MAX_VALUE;
return ThreadLocalRandom.current().nextInt(from, to);
}
@Override
public Object generate() {
return new IntegerGenerator().generate();
}
}
For custom IGenerators or IComplexGenerators that don’t require special annotation fields just use @GenCustom annotation that is provided by library to mark fields with your custom generators.
public class User {
@GenCustom(CustomComplexGenerator.class)
private String number;
}
Is required when you need properties for your IComplexGenerator.
@ComplexGen(CustomComplexGenerator.class)
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface GenInteger {
int from() default Integer.MIN_VALUE;
int to() default Integer.MAX_VALUE;
}
In case you want custom annotation for simple generator you can do it as well, just use @PrimeGen instead of @ComplexGen to mark your annotation.
This project licensed under the MIT - see the LICENSE file for details.