Hi Everyone,
I have a question regarding Sling Models and reusability in AEM.
In my project, we often create multiple components that need very similar backend logic. This sometimes leads to writing multiple Sling Models that look almost the same, with only small variations.
What is the best practice to avoid creating multiple similar Sling Models and instead build reusable, maintainable models that can be shared across components?
I’m looking for guidance on:
Recommended patterns for reusable Sling Models.
How to design models that work for multiple components
Whether to use inheritance, delegation, interfaces, or abstract models.
Any suggestions or examples would be really helpful.
Thank you!
Views
Replies
Total Likes
Hi @chandrasekhar79 ,
Are you trying to reuse the same Sling Model class for multiple components, or you want to share common logic between different models while still keeping separate models for each component?
Views
Replies
Total Likes
Hi @chandrasekhar79,
You can definitely avoid creating multiple similar Sling Models. A common approach is to break the logic into reusable pieces and let components share them instead of repeating code.
A few patterns that usually work well:
1. Create a base/abstract Sling Model
If several components share the same fields or helper methods, put that in an abstract model and let each component extend it. This keeps shared logic in one place and each component only overrides what’s unique.
Example:
@Model(adaptables = Resource.class)
public abstract class BaseCardModel {
@ValueMapValue
protected String title;
@ValueMapValue
protected String description;
protected String formatText(String text) {
return text.trim().toUpperCase();
}
}
Child model:
@Model(adaptables = Resource.class)
public class PromoCardModel extends BaseCardModel {
@ValueMapValue
private String promoTag;
public String getFormattedTitle() {
return formatText(title) + " - " + promoTag;
}
}
2. Use interfaces + one shared implementation
If multiple components need the exact same logic, define an interface (e.g., CardModel) and write one implementation. All components can then adapt to that same interface. It keeps things clean and avoids duplicate models.
Example:
public interface CardModel {
String getTitle();
String getDescription();
}
Shared model impl:
@Model(adaptables = Resource.class, adapters = CardModel.class)
public class CardModelImpl implements CardModel {
@ValueMapValue
private String title;
@ValueMapValue
private String description;
}
Use same model in multiple components:
<sly data-sly-use.cardModel="com.myproject.models.CardModel" />
3. Use delegation
If one component basically wraps another, you can use @Self / @Via / @Delegate to reuse another model directly instead of copying getters.
Example:
@Model(adaptables = Resource.class)
public class WrapperComponent {
@Self @Via("resource")
@Delegate
private CardModel baseModel;
public String getTitle() {
return baseModel.getTitle();
}
}
This avoids copying getters.
4. Move business logic to an OSGi service
If the repeated code isn’t tied to a specific component (like formatting, lookup logic, filters, etc.), put it in a service and inject it into multiple models. This is often the cleanest long-term option.
5. Consider resource type inheritance
If components share structure and logic, you can also reuse a model by setting sling:resourceSuperType, which automatically lets child components use the parent model.
In most real projects, a mix of abstract models + services + interfaces gives the best balance of reuse and flexibility.
Hi @chandrasekhar79 ,
The best practice to avoid creating multiple similar Sling Models is to separate common logic and make it reusable across components.
Create one reusable model (or helper) that holds all shared logic, and let each component’s model use it through interfaces, inheritance, or delegation. This avoids code duplication and keeps the project maintainable.
Hope this helps you.
These are examples:
1. Use Interfaces for Common Getter Methods:
Create an interface that defines shared fields/getters.
public interface CommonFields {
String getText();
String getAdress();
}Any component model can implement this and stay consistent across components.
2.Create an Abstract Base Model for Shared Fields & Logic :
If several components use the same data fields or logic, place them in an abstract base class:
@Model(adaptables = Resource.class)
public abstract class TestModel {
@ValueMapValue
protected String text;
@ValueMapValue
protected String adress;
public String getText() { return text; }
public String getAdress() { return adress; }
}Component-specific models can extend it:
@Model(adaptables = Resource.class)
public class ComponentModel extends TestModel {
// Component-specific logic
}
3. Use Model Delegation (@Self) :
This is cleaner than inheritance for large-scale projects.
@Model(adaptables = Resource.class)
public class DellModel {
@Self
private TestModel testModel;
public String getText() {
return testModel.getText();
}
} 4. Create Helper Models / OSGi Services for Reusable Utility Logic:
If multiple models require similar formatting or transformation logic, put it in a helper class:
public class ComponentUtils {
public String trim(String value) {
return value != null ? value.trim() : "";
}
}
Hope this examples will work
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies
Views
Likes
Replies
Views
Likes
Replies