
I would like to introduce the PetStore sample application, which demonstrates a pure "Java-first" approach to web interface development. The entire project is built on the idea of maximum type safety and clarity, achieved through two modules of the Ujorm 3 library. These effectively eliminate common abstraction layers that often complicate development and debugging. The PetStore is built on the lightweight Ujorm3 framework.
π οΈ Two Pillars of Ujorm3
1. UI Creation without Templates (ujo-web)
We have replaced traditional engines like Thymeleaf or JSP with pure Java code.
-
Type-safe rendering: HTML is generated using the
HtmlElementbuilder andtry-with-resourcesblocks. This approach allows writing Java code in a natural tree structure that faithfully mirrors the HTML structure. -
Refactoring with full IDE support: Since the UI is defined in Java, everything you are used to works β autocomplete (IntelliSense), instant refactoring (e.g., extracting a table into a
renderTable()method), and correctness checking while writing. -
No more parameter errors: The
HttpParameterinterface uses enums to define web parameters. This practically eliminates typos in form field names, which in standard solutions only manifest at runtime.
2. Modern Database Handling (ujo-orm)
Forget about complex XML mapping or runtime errors in SQL queries.
-
Using Java Records: Standard Java records serve as domain objects (
Pet,Category). They are naturally immutable, clean, and fully compatible with@Tableand@Columnannotations. -
Type-Safe SQL Builder: An annotation processor generates metamodels (e.g.,
MetaPet) during compilation. The compiler catches an error in a column name, not an application crash in production. -
SQL under control: No unexpected
LazyInitializationExceptionor hidden N+1 problems. You have absolute control over everySqlQuery. Moreover, you can easily map results from native SQL back to records using thelabel()method.
π Code Sample (PetServlet)
The project is designed with an emphasis on straightforwardness.
The following example from a stateless servlet demonstrates how elegantly logic, parameters, and HTML generation can be connected:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
var ctx = HttpContext.ofServlet(req, resp);
var contextPath = req.getContextPath();
var action = ctx.parameter(ACTION, Action::paramValueOf);
var petId = ctx.parameter(PET_ID, Long::parseLong);
var pets = services.getPets();
var categories = services.getCategories();
var petToEdit = (Action.EDIT.equals(action) && petId != null)
? services.getPetById(petId).orElse(null)
: null;
try (var html = HtmlElement.of(ctx, BOOTSTRAP_CSS)) {
try (var body = html.addBody(Css.container, Css.mt5)) {
renderHeader(body, contextPath);
renderTable(body, pets);
renderForm(body, petToEdit, categories);
}
}
}
Here is what a native SQL query looks like in pure Java:
static final EntityManager<Pet, Long> PET_EM =
EntityManager.of(Pet.class);
public List<Pet> findAll() {
var sql = """
SELECT p.id AS ${p.id}
, p.name AS ${p.name}
, p.status AS ${p.status}
, c.id AS ${c.id}
, c.name AS ${c.name}
FROM pet p
LEFT JOIN category c ON c.id = p.category_id
WHERE p.id >= :id
ORDER BY p.id
""";
return SqlQuery.run(connection.get(), query -> query
.sql(sql)
.label("p.id", MetaPet.id)
.label("p.name", MetaPet.name)
.label("p.status", MetaPet.status)
.label("c.id", MetaPet.category, MetaCategory.id)
.label("c.name", MetaPet.category, MetaCategory.name)
.bind("id", 1L)
.streamMap(PET_EM.mapper())
.toList());
}
π‘ Why Choose This Approach?
This architecture represents an interesting alternative for developers who are tired of heavy JPA frameworks or bloated frontend technologies.
Where Ujorm PetStore shines most:
- B2B and administrative applications: Where development speed and long-term maintainability are important.
- Microservices: Thanks to minimal overhead and fast startup.
- Projects with HTMX: It perfectly complements modern trends of returning to server-side rendering.
The "Java-First" philosophy drastically reduces context switching between Java, SQL, XML, and various templating languages.
Everything you need is under the protection of the compiler.
π Try It Locally
The application utilizes the best of the current ecosystem:
- Java 25
- Spring Boot 3.5.0
- H2 Database (In-memory)
All you need is JDK 25 and Maven installed, then just run:
mvn spring-boot:run
The application will start at http://localhost:8080.
Resources and Links:
- PetServlet.java β A stateless Servlet acting as both Controller and View. It handles HTTP communication and builds the HTML.
-
Dao.java β Data access layer integrating Spring JDBC with Ujorm
EntityManager. - Ujorm 3 Library on GitHub β Official library repository.
- ORM Benchmarks β How this approach compares to the competition.
Does it make sense to you to have the UI and DB layers so tightly coupled with the compiler? I will be glad for any technical feedback!
United States
NORTH AMERICA
Related News
Backfilling Is Harder Than Scraping: Lessons From Rebuilding 6 Months of Missing Data
April 1, 2026

How to Build an Android Document Scanner with Auto-Capture and PDF Export
April 1, 2026
I Built Cryptographic Proof for DeFi Liquidations Using Pyth Network
April 1, 2026
OpenClaw Workspace Architecture: The File System That Makes Agents Smart
April 1, 2026
How Ubiquitous Language Can Solve Your Miscommunication Issues
April 1, 2026
