u/Enough_Arrival_7335

▲ 3 r/javahelp+1 crossposts

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=false in your JPA annotation, the query engine automatically spins up an INNER JOIN. Otherwise, it defaults to a LEFT JOIN. No manual string stitching required.
  • Type-Safe Path Mapping: Notice the MetaEmployee.city, MetaCity.name chain? 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?

reddit.com
u/Enough_Arrival_7335 — 4 days ago