Spring Data JPA has one genuinely magical feature: you declare a query by naming a method. No SQL, no @Query, no implementation.
interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByStatusAndCustomerOrderByCreatedAtDesc(OrderStatus status, String customer);
}
Spring reads that name at startup and writes the query for you. It's wonderful — right up until you hit a method name and think "...wait, what does that actually generate?"
So I built a tool that shows you, live: type a method name, watch the JPQL and SQL appear.
▶ Live demo: https://dev48v.github.io/sql-to-jpa/
Source (zero dependencies): https://github.com/dev48v/sql-to-jpa
How the derivation works
Spring splits the method name into three parts:
find By StatusAndCustomer OrderByCreatedAtDesc
└subject┘ └─── predicates ───┘ └──── sorting ────┘
-
Subject —
find/read/get/query/count/exists/delete, plus optionalDistinctandTop/Firstlimits. -
Predicates — properties joined by
And/Or, each with an optional operator keyword. -
OrderBy — one or more properties, each
AscorDesc.
The example above becomes:
select o.* from orders o
where o.status = ? and o.customer = ?
order by o.created_at desc
The keywords are the whole language
The operator is a suffix on the property name, and there are a lot of them:
| Method fragment | SQL |
|---|---|
QuantityGreaterThan |
quantity > ? |
CreatedAtBetween |
created_at between ? and ? |
CustomerContaining |
`customer like '%'\ |
{% raw %}StatusIn
|
status in (?) |
ItemIsNull |
item is null |
ActiveTrue |
active = true |
CustomerIgnoreCase |
upper(customer) = upper(?) |
A couple of things that trip people up, made visible in the tool:
-
BetweenandInchange the parameter type.Betweentakes two args;Intakes aCollection. The generated signature reflects that. -
The return type comes from the subject.
count…→long,exists…→boolean,findFirst…/findTop1…→Optional<T>, otherwiseList<T>. -
Top3adds a limit that lives in SQL, not JPQL.
Why type it out instead of reading the docs
The grammar is simple in principle and fiddly in practice — GreaterThanEqual vs GreaterThan, where IgnoreCase goes, what Containing does with %. Poking at a live parser and watching the SQL change as you edit the name is faster than scanning a reference table, and it sticks better.
It's one index.html, no build, no dependencies — best-effort over a sample Order entity with the default camelCase → snake_case column naming.
If this saved you a "what does this generate?" moment, a star helps others find it: https://github.com/dev48v/sql-to-jpa
Top comments (0)