What is a custom fragment interface in Spring Data, and how does Spring find its implementation?
answer
- Fragment interface + Impl-postfix class
- Repository extends base AND fragment
- Discovered by classname convention, not @Component
- Constructor-injectable (EntityManager)
- Postfix configurable via repositoryImplementationPostfix
basics
~10 sA fragment is a small interface declaring custom repository methods you write yourself. Your repository extends it, and Spring finds the implementation class by name: the fragment interface name plus the suffix 'Impl'.
solid answer
~40 sSpring Data generates implementations for standard query and CRUD methods, but sometimes you need hand-written logic (a complex EntityManager query, a call to another system). You put that behavior behind a fragment interface — a plain interface declaring the method signatures. You then provide an implementation class whose name is the fragment interface name plus the 'Impl' postfix (e.g., OrderRepositoryCustom -> OrderRepositoryCustomImpl). Your actual repository interface extends both the standard base (like JpaRepository) and the fragment interface. At startup, Spring Data's repository infrastructure scans for the Impl class by convention, instantiates it (with constructor dependency injection), and composes it into the repository proxy. Callers just invoke the method on the repository; the proxy routes it to your Impl.
code
java · 28 lines// 1. Fragment interface — custom behavior
public interface OrderRepositoryCustom {
List<Order> findComplexOrders(SearchCriteria criteria);
}
// 2. Implementation — MUST be named <Fragment>Impl
public class OrderRepositoryCustomImpl implements OrderRepositoryCustom {
private final EntityManager em; // injected via constructor
public OrderRepositoryCustomImpl(EntityManager em) {
this.em = em;
}
@Override
public List<Order> findComplexOrders(SearchCriteria c) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> q = cb.createQuery(Order.class);
// ... build predicates from c ...
return em.createQuery(q).getResultList();
}
}
// 3. Repository extends BOTH the base and the fragment
public interface OrderRepository
extends JpaRepository<Order, Long>, OrderRepositoryCustom {
// derived + custom methods now both available on one bean
}go deeper
Know the three pieces and the Impl naming rule — that alone answers the common question.
Explain discovery by convention, constructor injection of EntityManager, and the configurable postfix.
Discuss composition into the proxy and the difference between the fragment and the generated base implementation.
Frame fragments as the boundary for imperative persistence code and set team conventions for naming/packaging.
## The problem fragments solve Spring Data repositories are interfaces you never implement — the framework generates a proxy at runtime that answers `save`, `findById`, derived queries like `findByEmail`, and `@Query` methods. But sometimes you need behavior the framework cannot derive: a hand-tuned JPA Criteria query, a call to `EntityManager` for a bulk update, full-text search, or integration with a non-JPA system. **Fragment interfaces** are the sanctioned extension point for that hand-written code. ## The three pieces 1. **The fragment interface** — a normal Java/Kotlin interface that declares the custom method signatures. Example: `interface OrderRepositoryCustom { List<Order> findComplexOrders(SearchCriteria c); }`. 2. **The fragment implementation** — a class that implements the fragment interface and contains the real logic. Its name **must** follow the convention: fragment-interface name + the postfix `Impl`. So `OrderRepositoryCustom` -> `OrderRepositoryCustomImpl`. This class is **not** annotated with `@Repository` or `@Component` (though it may be); it is discovered by the repository infrastructure, and it can declare constructor dependencies such as `@PersistenceContext EntityManager` (or just a constructor parameter) that Spring injects. 3. **The repository interface** — extends both a store-specific base (`JpaRepository<Order, Long>`) **and** the fragment interface: `interface OrderRepository extends JpaRepository<Order, Long>, OrderRepositoryCustom {}`. ## How discovery works During bootstrap, Spring Data's `RepositoryFactory` builds a **composition** of fragments for each repository. For every extended interface that is not the base repository, it looks for a matching implementation by classname convention (interface + `Impl`) on the classpath. It instantiates that class — resolving constructor arguments from the `ApplicationContext` — and registers it as a fragment. The runtime proxy that backs `OrderRepository` delegates `findComplexOrders` to your `OrderRepositoryCustomImpl` instance, and everything else to the generated base implementation (`SimpleJpaRepository`). ## The postfix is configurable The default `Impl` postfix comes from `@EnableJpaRepositories(repositoryImplementationPostfix = "Impl")`. You can change it globally (e.g., to `CustomImpl`) if you have a naming clash. ## Common gotchas - **Wrong Impl name** is the number-one failure: if the class is `OrderRepositoryCustomImplementation` or in a package outside the scanned base packages, Spring silently fails to compose it and you get a `Fragment ... has not been implemented` / `no implementation found` type error, or a `BeanCreationException` complaining the abstract methods aren't backed. - The Impl class implements **only the fragment**, not the whole repository — it must not try to implement `JpaRepository`. - Historically (pre Spring Data 2.0) there was a single 'custom' interface; the modern model allows **many** fragments per repository. ## When to use Reach for a fragment whenever a repository method needs imperative code the framework can't derive. Keep the fragment small and cohesive; if it grows, split into multiple fragments.
- Does the Impl class need an @Repository or @Component annotation?No. The repository infrastructure discovers it by the classname convention and instantiates it as a fragment, wiring constructor dependencies from the context. You may annotate it, but it is not required.
- What error do you get if the Impl class is misnamed?Spring fails to compose the fragment, so the repository proxy has an unbacked abstract method — typically a startup BeanCreationException / 'no fragment implementation found' style error rather than a runtime NPE.
saying these in an interview costs you the question
- Thinking the Impl class must implement the whole JpaRepository, not just the fragment
- Believing the Impl must be annotated @Component/@Repository to be picked up
- Naming the class anything other than <Fragment>Impl and expecting it to work