Skip to content

storm-orm/storm-example-java-spring-boot-4

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Storm Movies — Java + Spring Boot 4 example

An example movie browser built with Storm ORM on Spring Boot 4 and Java 21. It imports the public IMDB dataset into PostgreSQL and serves a server-rendered web app (Thymeleaf + a little vanilla JS) for browsing movies, people, genres, ratings, and a watchlist.

The project exists to show what idiomatic Storm looks like in a real Spring Boot application: immutable record entities, metamodel-based queries, Spring-managed transactions, and schema validation — no JPA, no proxies, no persistence context.

Stack

  • Java 21, Spring Boot 4.1 (WebMVC + Thymeleaf, virtual threads enabled)
  • Storm ORM (storm-spring-boot-starter + storm-java21) with the annotation-processor metamodel generator and RAW SQL string templates
  • PostgreSQL 17 (Docker Compose) with Flyway migrations
  • Jackson (storm-jackson3) for the JSON APIs and cache values, including Storm's Ref serialization
  • JUnit 5 + storm-test on H2 for repository tests, Playwright for interface tests

Java 21 preview features

Storm's Java API builds SQL with JDK String Templates (JEP 430), a preview feature that shipped in Java 21 and 22 and was then withdrawn. The project therefore pins the toolchain to Java 21 specifically and enables preview features everywhere: --enable-preview is wired into every JavaCompile task, every Test task, and bootRun in build.gradle.kts. The app must be built and run on a Java 21 JDK — later JDKs no longer have the feature. The RAW."... \{expression} ..." syntax you see in the repositories is that preview feature in action; the interpolated \{...} values are separated from the SQL fragments at compile time, so the templates are injection-safe by construction.

String templates were withdrawn for a redesign, not abandoned: Project Amber is reworking the feature, and a revised proposal is expected to return to the JDK. Storm deliberately ships String Template support today rather than waiting — the Java API is production-ready, and its template syntax will track the redesigned feature as it lands. Once string templates return to the JDK as a stable feature, the Java API moves front and center alongside Kotlin, without preview flags or a version pin. Everything else in this example — entities, repositories, the metamodel, transactions — is stable Java and unaffected by the preview status.

Running the application

Prerequisites: JDK 21 and Docker.

# 1. Start PostgreSQL
docker compose up -d

# 2. Start the application
./gradlew bootRun

# 3. Open the app
open http://localhost:8080

On first startup the app runs the Flyway migration and imports the IMDB dataset: movies with at least 1,000 votes (configurable via imdb.import.minimum-vote-count), plus their genres, cast, crew, and ratings. The dataset files (~1.2 GB) are downloaded once and cached in ./data, then streamed through Storm's batch inserts — expect the first startup to take a few minutes. The import is skipped entirely on subsequent startups once movie data is present.

To start over with an empty database:

docker compose down -v

Movie posters, person photos, and plot summaries are fetched at runtime from the IMDB suggestion API and the Wikipedia REST API, so the app looks best with internet access.

Project layout

src/main/java/st/orm/demo/imdb/
├── model/          Storm entities (@PK, @FK) and projections, as records
├── repository/     EntityRepository interfaces with QueryBuilder queries
├── service/        Business logic in @Transactional service methods,
│                   plus the streaming IMDB importer
├── web/            MVC controllers (pages) and REST controllers (/api/**)
└── serialization/  Jackson support: custom serializers and the
                    JSON-serialized Spring cache
src/main/resources/
├── db/migration/   Flyway schema (V1__create_schema.sql)
├── templates/      Thymeleaf views
└── static/         CSS, JS, images

What to look at

Each part of the app demonstrates a Storm feature:

  • Entities (model/) — immutable records with @PK, @FK, @UK, and composite keys (MovieGenre, Principal). MovieView is a Ref-backed entity; MovieSummary / PersonSummary are database-view-style projections that select a subset of columns.
  • Repositories (repository/) — EntityRepository interfaces with default methods using the type-safe QueryBuilder and generated metamodel (Movie_.startYear, Principal_.person). Aggregations return plain records; computed expressions use RAW SQL string templates with metamodel references.
  • Transactions (service/) — Spring's declarative @Transactional at the service level. Storm's Spring integration binds repository operations to the active transaction, so the writes on a request either all commit or all roll back. The two operations with a non-trivial boundary (the importer and the gallery service) use Spring's programmatic TransactionTemplate.
  • Streaming import (service/ImdbDataImporter.java) — a Stream-based pipeline that parses TSV rows into entities and hands them to Storm's batch insert, one pass per file, without materializing entity lists.
  • Schema validation — on by default: the starter verifies every entity against the live database schema at startup; EntitySchemaValidationTest does the same in the test suite.
  • Serialization (serialization/, web/ API models) — Storm entities serialized with Jackson for the REST endpoints (Ref fields via storm-jackson3, BigDecimal and Instant via field serializers), and a Spring cache that stores values as serialized JSON to prove entities survive the round-trip (CacheConfiguration.java).

Testing

./gradlew test

Repository tests run on an in-memory H2 database via @StormTest — no Docker required. Tests receive an ORMTemplate and a SqlCapture as parameters, so they can assert on the SQL Storm generates.

The Playwright interface tests run against a live application:

./gradlew installPlaywrightBrowsers   # once
./gradlew bootRun                     # in one terminal
./gradlew e2eTest                     # in another

Configuration

Everything lives in src/main/resources/application.yaml. The defaults match the Compose file (database imdb, user/password storm on localhost:5432). Import behavior is tunable under imdb.import (cache directory, minimum vote count, dataset base URL).

Learning more

About

Example movie browser built with Storm ORM on Spring Boot 4 and Java 21 (preview features), using the public IMDB dataset

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors