Sling Model snippets
Purpose: Model skeletons for the recurring shapes: component model, child resources, delegation, exporter.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Daily |
Standard component model (request-adapted)
@Model(adaptables = SlingHttpServletRequest.class,
adapters = PlanCardModel.class,
resourceType = "phi-academy/components/plancard",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class PlanCardModel {
@ValueMapValue private String title;
@ValueMapValue @Default(values = "") private String subtitle;
@ValueMapValue @Default(doubleValues = 0) private double monthlyPremium;
@ChildResource private List<BenefitItem> benefits;
@ScriptVariable private Page currentPage;
@OSGiService private PremiumFormatter formatter;
private String formattedPremium;
@PostConstruct void init() {
formattedPremium = formatter != null ? formatter.format(monthlyPremium) : "";
if (benefits == null) benefits = Collections.emptyList();
}
public String getTitle() { return title; }
public String getFormattedPremium() { return formattedPremium; }
public List<BenefitItem> getBenefits() { return benefits; }
public long getCoveredCount() {
return benefits.stream().filter(BenefitItem::isCovered).count();
}
}
Child item model (multifield rows)
@Model(adaptables = Resource.class,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class BenefitItem {
@ValueMapValue @Default(values = "") private String label;
@ValueMapValue @Default(booleanValues = false) private boolean covered;
public String getLabel() { return label; }
public boolean isCovered() { return covered; }
}
JSON exporter variant
@Model(adaptables = SlingHttpServletRequest.class,
adapters = { PlanCardModel.class, ComponentExporter.class },
resourceType = "phi-academy/components/plancard",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class PlanCardModel implements ComponentExporter {
// fields as above …
@Override public String getExportedType() { return "phi-academy/components/plancard"; }
@JsonIgnore public Page getCurrentPage() { return currentPage; } // keep internals out
}
Core Component delegation
@Model(adaptables = SlingHttpServletRequest.class, adapters = Title.class,
resourceType = "phi-academy/components/title",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class PhiTitle implements Title {
@Self @Via(type = ResourceSuperType.class) private Title delegate;
@Override public String getText() { return delegate == null ? null : delegate.getText().toUpperCase(); }
@Override public String getType() { return delegate == null ? null : delegate.getType(); }
}