What is Sort.TypedSort and what advantage does it give over Sort.by(String...)?
answer
- Sort.sort(Entity.class) -> TypedSort<T>
- method references, not Strings
- compile-time safe + refactor-proof
- proxy records the getter's property path
- no help for runtime-chosen sort fields
basics
~10 sSort.TypedSort lets you build a Sort from method references instead of String property names, so sort fields are checked by the compiler and survive refactoring/renames. You get it via Sort.sort(EntityClass.class).
solid answer
~50 sSort.TypedSort is a type-safe way to construct a Sort. Instead of Sort.by("firstName") — a String that no compiler validates — you call Sort.sort(Person.class) to obtain a TypedSort<Person>, then reference the property with a getter method reference: Sort.sort(Person.class).by(Person::getFirstname).descending(). It works by returning a proxy of the entity; invoking the getter records the property path, which TypedSort turns into a real Sort (TypedSort extends Sort). The benefit is compile-time safety: a typo or a renamed field becomes a compilation error rather than a runtime PropertyReferenceException, and IDE rename-refactoring updates the sort automatically. You can chain via and(...) for multiple keys and it supports nested paths by chaining getters. The cost is a small proxy overhead and getters that must follow JavaBean conventions. It shines when sort keys are hardcoded in code; it does not help when the sort field comes dynamically from a request.
code
java · 9 lines// Type-safe sort via method references
Sort typed = Sort.sort(Person.class)
.by(Person::getLastname).ascending()
.and(Sort.sort(Person.class).by(Person::getCreatedAt).descending());
Page<Person> page = personRepository.findAll(PageRequest.of(0, 20, typed));
// Renaming Person#getLastname in the IDE updates this call automatically;
// the String form Sort.by("lastname") would silently break at runtime.go deeper
Awareness only: it's a type-safe alternative to Sort.by(String).
Know Sort.sort(Class) + getter method references give compile-time-checked, refactor-safe sorts.
Explain the proxy mechanism, chaining/nesting, and that it only helps for code-defined (not dynamic) sorts.
Decide where the team mandates typed sorts (internal defaults) vs. whitelisted String sorts (external input), balancing safety against proxy constraints.
**The problem with String-based Sort.** `Sort.by("firstName")` uses a *String* property name. Nothing checks it at compile time: misspell it, or rename the entity field later, and you get a runtime `PropertyReferenceException` (or a silently wrong sort). Refactoring tools can't reliably update the String either. **What TypedSort is.** `Sort.TypedSort<T>` is a subclass of `Sort` that builds the ordering from **method references** to getters instead of Strings. You obtain one with the static factory `Sort.sort(Class<T>)`: ```java TypedSort<Person> person = Sort.sort(Person.class); Sort sort = person.by(Person::getFirstname).descending(); ``` **How it works.** `Sort.sort(Person.class)` returns a `TypedSort<Person>` backed by a **proxy** of `Person`. When you call `by(Person::getFirstname)`, the method reference is invoked against that proxy; the proxy records which property/getter was accessed and derives the property path (`firstname`). `TypedSort` then produces a normal `Sort` from that path. Because `TypedSort` *extends* `Sort`, the result is usable anywhere a `Sort` is expected — repository methods, `PageRequest.of(page, size, sort)`, etc. **Fluent API.** After `.by(getter)` you can call `.ascending()` / `.descending()`, and chain additional keys with `.and(...)`: ```java Sort sort = Sort.sort(Person.class) .by(Person::getLastname).ascending() .and(Sort.sort(Person.class).by(Person::getCreatedAt).descending()); ``` Nested properties are expressed by chaining getters through the object graph (the proxy walks into the returned type), e.g. sorting by `address.city` via `by(Person::getAddress)` into the nested getter, depending on API form. **The advantage.** - **Compile-time safety** — a wrong or removed property is a *compilation* error, not a production runtime error. - **Refactor-friendly** — IDE renames of the getter/field update the sort automatically; String-based sorts silently rot. - **Discoverability** — autocomplete surfaces valid properties. **Constraints / gotchas.** - Requires **JavaBean-style getters**; the property must be reachable via a getter method reference. Fields without getters can't be referenced. - There's minor **proxy creation overhead** — negligible for typical use but it's not free. - It only helps when the sort key is **known in code**. If the sort property is chosen dynamically at runtime (from a request parameter), you're back to Strings (and must whitelist them). - It's a Spring Data feature; the entity class needs to be proxyable (non-final getters/class in some setups). **When to use.** Hardcoded, code-defined sort orders in queries or services where you value refactoring safety — internal default sorts, fixed report orderings. Skip it for user-driven dynamic sorting.
- Does TypedSort help when the sort column comes from a REST query parameter?No. A runtime String from the request can't be a compile-time method reference, so you fall back to Sort.by(String) — and you must whitelist the allowed properties to avoid errors and field enumeration.
- How does TypedSort capture the property from Person::getFirstname?Sort.sort(Class) returns a proxy of the entity; invoking the getter method reference on that proxy records which property was accessed, and TypedSort converts that recorded path into a normal Sort.
saying these in an interview costs you the question
- Claiming TypedSort works on fields without getters
- Thinking it helps with dynamic, request-driven sort fields
- Believing it returns something other than a Sort (it extends Sort)
- Assuming it has zero overhead / needs no proxy