Type-safe SQL in Java without the bloat: Inferred JOINs based on JPA annotations
Hi everyone,
I’ve been working on a lightweight ORM module for Ujorm3, aiming for a sweet spot between raw native SQL safety and the heavy weight of full-blown ORMs like Hibernate.
One of the neat features we implemented is automatic JOIN type resolution derived directly from standard JPA metadata (like nullable=false), combined with a compile-time generated metamodel.
Here is a quick look at how a SelectQuery handles relations, multiple tables, and custom SQL tails fluently:
final var ctx = EntityContext.ofDefault();
final var employeeEm = ctx.entityManager(Employee.class);
List<Employee> select(Connection connection) {
return SelectQuery.run(connection, employeeEm, query -> query
.sql("SELECT") // Optional custom start
.columns(true) // Loads all table columns including foreign keys
.column(MetaEmployee.city, MetaCity.name) // Auto-generates INNER JOIN
.column(MetaEmployee.boss, MetaEmployee.name) // Auto-generates LEFT JOIN
.where(MetaEmployee.id.whereGe(1L).and(MetaCity.id.whereGe(1L)))
.tail("ORDER BY", MetaEmployee.id) // Optional custom end
.toList()
);
}
How it works under the hood:
- Zero Reflection at Runtime: The library compiles its own bytecode at runtime for lightning-fast domain object manipulation, matching the speed of handwritten Java.
- Smart JOINs: If a mandatory object attribute is marked as
nullable=falsein your JPA annotation, the query engine automatically spins up anINNER JOIN. Otherwise, it defaults to aLEFT JOIN. No manual string stitching required. - Type-Safe Path Mapping: Notice the
MetaEmployee.city, MetaCity.namechain? It provides a compile-time safe path for multi-relational mappings, backed by an APT processor.
The goal here was keeping the codebase minimalistic to extend maintainability and eliminate runtime surprises (like dreaded lazy-loading exceptions, since we chose not to support lazy-loading at all).
I'd love to hear your thoughts on this approach! Do you prefer your SQL builders strictly native, or do you like this level of automation?