Skip to content

About

JPA-aware fake data seeding for Spring Boot

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

SynthForge

A JPA-aware fake data seeding library for Spring Boot.

Instancio (and its instancio-jpa extension) gives you an API to call from inside a test - build a graph, persist it, for that test. SynthForge runs itself: annotate the entity, start the app in a dev profile, and the database is already populated - no test method, no calling code, anywhere.

The problem

Faker and Datafaker generate realistic-looking values - names, emails, addresses - but they have no idea your entities are related. The moment one entity references another (Payment → Counterparty), you're back to hand-writing a seed script: create parents first, hold onto their IDs, wire them into children, hope you didn't violate a @NotNull or a unique constraint along the way. That script rots the first time a field changes. SynthForge reads your JPA entities directly - annotations, relationships, and all - and generates a valid, related, constraint-respecting object graph with a single annotation, so there's no script to write or maintain.

Install

SynthForge is on Maven Central. Add the dependency to your own Spring Boot project:

Maven

<dependency>
    <groupId>io.github.thembatman0</groupId>
    <artifactId>synthforge-spring</artifactId>
    <version>0.1.0</version>
</dependency>

Gradle

implementation 'io.github.thembatman0:synthforge-spring:0.1.0'

Requires Java 21 and Spring Boot with Spring Data JPA. The test suite passes in CI on both Spring Boot 4.1 and Spring Boot 3.5.16. Spring Boot 3.5 apps still need to run on Java 21 or newer, because the library is compiled for Java 21.

Try it in two minutes

The repo includes a small demo app (Counterparty and Payment on an in-memory H2 database). From a fresh clone:

git clone https://github.com/ThembaTman0/synthforge.git
cd synthforge
mvn -pl synthforge-demo -am install -DskipTests
mvn -pl synthforge-demo spring-boot:run -Dspring-boot.run.profiles=dev

Along with the SQL it logs (show-sql is on), you should see:

SynthforgeAutoConfiguration : Seeding with random seed 1593487635758507864 (set synthforge.seed to this value to reproduce the run)
SynthforgeAutoConfiguration : Seeded 50 Counterparty rows
SynthforgeAutoConfiguration : Seeded 200 Payment rows

The seed value will differ on each run. Set synthforge.seed to a fixed number to get identical data every time. The demo has no web layer, so it seeds, logs and exits. To see seeding work in your own app, annotate an entity as shown under "Before / after" below.

When it is not the right tool

  • You want a fresh object graph inside a single test method. That is what Instancio is for.
  • You need data in production. Seeding is for dev and test profiles only, and is off unless you list a profile under synthforge.enabled-profiles.
  • You need to load very large volumes. Seeding is meant for dev and test data sizes and goes through JPA's EntityManager; it has not been designed or measured for bulk loads.
  • Your model depends on @OneToMany/@ManyToMany collections or composite keys. Those fields are skipped in this release.

Building from source (for contributing to SynthForge itself, not needed just to use it): mvn install.

Before / after

Without SynthForge, seeding two related entities means a hand-wired script:

List<Counterparty> parents = new ArrayList<>();
for (int i = 0; i < 50; i++) {
    parents.add(counterpartyRepo.save(new Counterparty(faker.name().fullName(), faker.internet().emailAddress())));
}
for (int i = 0; i < 200; i++) {
    paymentRepo.save(new Payment(parents.get(random.nextInt(parents.size())), randomAmount()));
}

With SynthForge, the entities are the seed script:

@Entity @Seed(count = 50)
public class Counterparty { /* fields only */ }

@Entity @Seed(count = 200)
public class Payment {
    @ManyToOne(optional = false) private Counterparty counterparty; // wired automatically
}

Enable it for the profiles you want (never production):

synthforge:
  enabled-profiles: [dev, test]

Start the app in an enabled profile and both tables are populated, in the right order, with realistic values, on every restart.

How it works

  • Entity scanning - reads JPA-managed attributes through the jakarta.persistence.metamodel.Metamodel API, never raw reflection, so only real persistent fields are ever touched.
  • Relationship ordering - builds a dependency graph from owning-side @ManyToOne/@OneToOne relationships and topologically sorts it, so parent rows always exist before a child is generated to reference them.
  • Constraint-aware generation - @NotNull, @Size, @Email, and field-name heuristics (email, iban, amount, country, ...) drive realistic values via Datafaker; a @Column(unique = true) field gets a bounded retry loop instead of a constraint violation.
  • Idempotent restarts - a table that already has rows is skipped, so restarting against a persistent database never duplicates seed data.

Full technical detail - the exact resolution priority, relationship rules, and configuration reference - is in synthforge-v1-spec.md.

License

MIT

About

JPA-aware fake data seeding for Spring Boot

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages