HomeCore Learning Journey › Session 5 — Sling Models

Session 5 — Sling Models

Purpose: Move logic out of templates into Sling Models — the custom hooks of AEM — with injection, defaults and exporters.

Who this page is for

AudienceWhy it matters to you
Backend engineersCore daily skill
Frontend engineersYou need to read these fluently

The custom-hook of AEM

A Sling Model adapts a resource (raw content) into a typed, view-ready API — exactly the job of a custom hook adapting store state for a component. HTL stays dumb; the model owns logic.

@Model(adaptables = SlingHttpServletRequest.class,
       adapters = PlanCardModel.class,
       defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class PlanCardModel {

    @ValueMapValue
    private String title;                       // ← like reading a store field

    @ValueMapValue @Default(doubleValues = 0)
    private double monthlyPremium;

    @ChildResource
    private List<Benefit> benefits;             // ← multifield rows

    public String getFormattedPremium() {       // ← derived state lives HERE,
        return String.format("$%.2f / month", monthlyPremium);   //   not in HTL
    }
    public boolean isAffordableTier() { return monthlyPremium < 300; }
    public String getTitle() { return title; }
    public List<Benefit> getBenefits() { return benefits; }
}

Injection annotations you will actually use

AnnotationInjectsHook analogy
@ValueMapValueA property of the current resourceuseSelector(s => s.x)
@ChildResourceChild node(s), optionally adapted to classesSelecting a slice of rows
@SelfThe adaptable itself (request/resource)Hook context
@OSGiServiceA backend serviceuseContext(ServiceContext)
@ScriptVariablePage-level objects (currentPage, pageManager)Router/context objects
@RequestAttributeA request attribute (e.g. passed by data-sly-resource)Props from parent
@PostConstruct methodRuns after injection — derive/validate hereThe hook body

Rules of thumb

Exporters: your model as JSON

Add @Exporter(name = "jackson", extensions = "json") (Sling Model Exporter) and the same model that feeds HTL serves headless clients at resource.model.json — one adapter, two channels. This is how AEM SPA/headless delivery works under the hood.

Quick navigation