skip to content

Custom Fragment Interfaces

Custom behaviour is added through fragment interfaces with matching Impl classes, several of which can be composed into one repository. The standard answer to 'how do you add a hand-written query without abandoning the repository'.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is a custom fragment interface in Spring Data, and how does Spring find its implementation?

level: juniorimportance: must knowfreq 55%

answer

  1. Fragment interface + Impl-postfix class
  2. Repository extends base AND fragment
  3. Discovered by classname convention, not @Component
  4. Constructor-injectable (EntityManager)
  5. Postfix configurable via repositoryImplementationPostfix

basics

~10 s

A 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 s

Spring 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
java
// 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

for a junior

Know the three pieces and the Impl naming rule — that alone answers the common question.

for a middle

Explain discovery by convention, constructor injection of EntityManager, and the configurable postfix.

for a senior

Discuss composition into the proxy and the difference between the fragment and the generated base implementation.

for a principal

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

context

open as a page

How do you compose multiple fragment interfaces into one repository, and why would you split behavior across several fragments?

level: middleimportance: should knowfreq 40%

basics

~20 s

A repository interface can extend several fragment interfaces at once. Each has its own Impl class. You split behavior so unrelated custom logic (e.g., search vs. reporting) stays in small, cohesive, independently testable units instead of one giant custom class.

open as a page

Explain the method-resolution order Spring Data uses across fragments and the base repository. How would you override a CRUD method like save()?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Spring Data checks fragments in the order you declared them in the repository's extends clause; the first fragment that declares the method handles the call. Fragments outrank the generated base, so declaring a fragment with save() (listed before the base is implicitly) lets it override the default save().

open as a page

How does Spring Data discover a fragment's Impl class, and how do you handle a non-default postfix or a manually-configured fragment bean?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

Spring scans the repository's base packages for a class named <Fragment>Impl and instantiates it, injecting constructor dependencies. You can change the 'Impl' suffix via repositoryImplementationPostfix, or register the Impl as an explicit Spring bean when it needs special wiring.

open as a page

Compare default methods on a repository interface with fragment implementations. When do you choose each, and how do they interact with the base implementation and derived queries?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

Default methods live on the interface and are run directly by the proxy — good for simple logic that just composes existing repository methods, with no Impl class. Fragments are separate classes for real custom logic needing injected collaborators (EntityManager, external clients) and can override CRUD methods.

open as a page