Skip to content

kuros/random-jpa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Random-JPA Build Status Coverage Status Maven Central

It has been always been a challenge to create a test data. This project aims at providing easier mechanism to create test data.

Maven Group Plugin java version Latest Version
com.github.kuros.random-jpa 1.5+ v0.6.6
com.github.kuros.random-jpa 1.8+ v1.0.4

Feature

  1. Uses table's foreign key relations to maintain creation order dynamically
  2. Creates in memory creation plan which can be used to modify column values before persist.
  3. Provides facility to add custom dependency.
  4. Provides facility to add random generator (both at class level and attribute level).
  5. You can print the creation plan and persisted object hierarchy and easily access the respective objects by index.

Supported Database

  1. Microsoft SQL Server
  2. MySQL
  3. Oracle
  4. Postgres
  5. NONE (You can still use functionality, but the dependency has to provided/maintained manually).

Supported JPA Implementation

  1. Hibernate (Version - 4.x, 5.x)
  2. EclipseLink

Usage

In order to use.

Initialize JPAContextFactory

JPAContextFactory accepts two parameters Database and EntityManager. I am using MS_SQL_SERVER for demo.

JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
    .generate();

Initialization with Dependencies

Let us say that you want have a custom dependency between Person and Employee tables but you do not have any foreign key relationship between them. We will have create Dependencies for this using javax.persistence.metamodel.Attribute objects. (Here Person_ & Employee_ are SingularAttributes)

final Dependencies dependencies = Dependencies.newInstance();
dependencies.withLink(Link.newLink(Person_.id, Employee_.personId))

JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
    .with(dependencies)
    .generate();

Creating RandomGenerators

There are two ways in which you can control the random generation behavior.

  • At Class level
  • At Attribute level.

Let us say that you want all the dates to be current date. And all the Long/Integer values to be positive between 0-1000

final Generator generator = Generator.newInstance();
generator.addClassGenerator(new RandomClassGenerator() {
            @Override
            public Collection<Class<?>> getTypes() {
                final List<Class<?>> classes = Lists.newArrayList();
                classes.add(Date.class);
                return classes;
            }

            @Override
            public Object doGenerate(final Class<?> aClass) {
                return new Date();
            }
        });

generator.addClassGenerator(new RandomClassGenerator() {
            @Override
            public Collection<Class<?>> getTypes() {
                final List<Class<?>> classes = Lists.newArrayList();
                classes.add(Long.class);
                classes.add(Integer.class);
                return classes;
            }

            @Override
            public Object doGenerate(final Class<?> aClass) {
                return org.apache.commons.lang.RandomUtils.nextInt(1000);
            }
        });

You can also override random generation for specific attributes, to do that use RandomAttributeGenerator. Let us say that you want all the employee name to start with "Test-" followed by random string.

generator.addAttributeGenerator(new RandomAttributeGenerator() {
            @Override
            public List<? extends Attribute> getAttributes() {
                final List<SingularAttribute> singularAttributes = new ArrayList<SingularAttribute>();

                singularAttributes.add(Employee_.state);
                return singularAttributes;
            }

            @Override
            public Object doGenerate() {
                return "Test-" + RandomStringUtils.randomAlphanumeric(2);
            }
        });

Initializing RandomGenerators

final JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
                .with(generator)
                .generate();

Adding Preconditions

There are scenario's where we want to create some schema in advance before creating our table, and this schema doesn't fall under the hierarchy of main table. To handle such scenarios, we can define PreConditions

final JPAContext jpaContext = JPAContextFactory.newInstance(Database.MS_SQL_SERVER, entityManager)
                .withPreconditions(Before.of(Employee.class)
                                            .create(Entity.of(Department.class), Entity.of(XXX.class)),
                                   Before.of(Person.class)
                                            .create(Entity.of(Y.class), Entity.of(Z.class)))
                .generate();

Using JPAContext

Creating Plan

Once JPAContext is initialized, you can use it to create plans and persist them accordingly. Let us say that we want to create two different Employees referring to single Person Or

CreationPlan creationPlan = jpaContext.create(
            Entity.of(Employee.class, 2).with(Employee_.Country, INDIA),
            Entity.of(Person.class).with(Person_.gender, "Male"));

Modify the creationPlan

Let us say that I want to persist these two employees with different name.

creationPlan.set(Employee_.name, "Employee 1");

creationPlan.set(1, Employee_.name, "Employee 2");

Printing the creationPlan

You need to provide a printer, which will print the string.

creationPlan.print(new Printer() {
            @Override
            public void print(final String string) {
                System.out.println(string); // you can use logger
            }
        });

it will print the hierarchy with the index number of the object followed by

└── *ROOT*
    └── com.github.kuros.entity.Person|0
        ├── com.github.kuros.entity.Employee|0
        └── com.github.kuros.entity.Employee|1

Persisting the creationPlan

final ResultMap resultMap = jpaContext.persist(creationPlan);

You can also create and persist plans

final ResultMap resultMap = jpaContext.createAndPersist(
            Entity.of(Employee.class, 2).with(Employee_.Country, INDIA),
            Entity.of(Person.class).with(Person_.gender, "Male"));

Fetching the persisted objects

Employee emp1 = resultMap.get(Employee.class);
System.out.println(emp1.getName()); // Prints - Employee 1

Employee emp2 = resultMap.get(Employee.class, 1);
System.out.println(emp2.getName()); //Prints - Employee 2

Printing the Persisted objects

You need to provide a printer, which will print the string.

resultMap.print(new Printer() {
            @Override
            public void print(final String string) {
                System.out.println(string); // you can use logger
            }
        });

it will print the hierarchy with the index number of the object followed by the primary key of the persisted objects

└── *ROOT*
    └── com.github.kuros.entity.Person|0 [personId: 1]
        ├── com.github.kuros.entity.Employee|0 [employeeId: 1]
        └── com.github.kuros.entity.Employee|1 [employeeId: 2]

** Id's might not get printed for all the loaded entities, since some entities are lazily initialized.

For More details please follow Random-JPA Blogls -l