Our Blog

Sling Model

Objectives

After reading this article, you should have an

  • Understand of Sling Models
  • Benefits of Sling Models
  • Understand how to use Sling Models in an HTL template

Development Goals

Sling Models are available since AEM 6.0 but can also be installed in CQ 5.6.1.
Main advantages of using Sling Models are

  1. Reusability
    You can write your code based on design patterns. If you use Sling Models you can remove all business logic from JSP and do not scriplets.
  2. Maintenance
    It’s easier to test Sling Models, because they are Java classes and can be covered with unit test. Also, it’s easier to add logging.
  3. Scalability
    Costs for introducing of new developers are lower And development is faster.

What is Sling Models? – Old Approach

public class OldModel {
   private String title;
   private String decription;
   public String getTitle(){ ... }
   public void setTitle(String title){ ... }
   public String getDescription(){ ... }
   public void setDescription(String description){ ... }
}


Let’s get familiar with the life before Sling Models. Let’s look at this eg. Let’s say you need to Adapt a resource to the class which has number of properties, such as title & description for that we need to create a Java bean with private fields, getters & setters.

@Component
@Service
@Properties({
 @Property(name = AdapterFactory.ADAPTABLE_CLASSES, value="org.apache.sling.api.Resource"),
 @Property(name = AdapterFactory.ADAPTER_CLASSES, value="...OldModel")
})
public class OldModelAdapterFactory implements AdapterFactory {
  public <AdapterType> AdapterType getAdapter(Object adaptable, Class <AdapterType> type) {
     if(adaptable instanceof Resouce && type.equals(OldModel.class)) {
         OldModel model = new OldModel();
         ValueMap map = ResourceUtil.getValueMap((Resource)adaptable);
         model.setTitle(map.get("title",String.class));
         model.setDescription(map.get("description",String.class));
         return (AdapterType)model;
     } else {
         return null;
  }
}

After that we need to implement AdapterFactory interface & specify that sling resource should be adaptable to our custom Java bean & logic of adaptation read values from the resource & set these values to our model class.

OldModel myModel = resource.adaptTo(OldModel.class)

<sling:adaptTo adaptable="${resource}" adaptTo="...oldModel" var="myModel"
<div data-sly-use.myModel="...OldModel"></div>

Finally, we can use AdapTo method & get our model object with values from resource we are adapting from.
Or we can use sling:adapTo tag to the resource in a JSP file.


So older approach steps are

  1. Create Java Bean Class
  2. Create AdapterFactory
  3. Use sling:adapTo tag

New Approach

@Model(adaptables = Resource.class)
 public class NewModel {

	@Inject
	private String title;

	@Inject
	private String decription;

	public String getTitle(){ return title; }

	public String getDescription(){ return description; }
 }



<div data-sly-use.myModel."...NewModel"></div>

New approach with Sling Models is much easier & more intuitive, We just need to create a sling model class & then use it.

To create a Sling Model you should mark your class as adaptables from resource & mark fields which should be populated from the resource properties using Inject annotation & don’t forget to create getters for your fields.

data-sly-use statement is used to initialize sling model in an HTL template.

Resource Data in POJO

Here you can see an example of mapping between resourcing their repository & Sling Model.

To mark Java class as a Sling Model use annotation Model for adapting functionality we mark Resource like adaptables from sling resource by specifying property inside Model annotation.

It’s also possible to adapt from a SlingRequest. For populating properties of a sling model, we use a Inject annotation.

What can be injected?

  • Script Variables (Sling Bindings)
  • Value Map (Resource properties)
  • Child Resources
  • Request Attribute
  • OSGi Service References

Annotation Reference

What annotations are available in a Sling Model?

@Model – declares a model class or interface

@Inject –  makes a field or method as injectable

@Named – declares a name for the injection (otherwise, defaults based on field or method name).

@Optional – marks a field or method injection as optional

@Source – explicitly tie an injected field or method to a particular injector (by name). Can  also be on other annotations.

@Filter – an OSGi service filter

@PostConstruct – methods to call upon model option creation (only for model classes)  @Via – makes a JavaBean property of the adaptable as the source of the injection

@Default – declares default values for a field or method

Setting Up

<Sling-Model-Packages>
    org.apache.sling.models.it.models,
    org.apache.sling.other.models
</Sling-Model-Packages>

To start using Sling Model you need to create a separate bundle for Sling Models, is not required but recommended & specify Sling-Model-Packages, a header in the bundle manifest.

Available Injectors

When you use Inject annotation sling will execute all available Injectors into values are set.
The top priority is
1. Script Bindings – Injector which lookup objects in the script bindings object, like currentPage, currentNode & so on.
2. Value Map – will get a property from ValuMap object of resource.
3. Child Resources – Injector will get a child resource by name.
4. Request Attribute – injector will get a request attribute.
5. OSGI Services – a services will lookup service based on class name.

You can find all available injectors in Felix Console by below link.

http://localhost:4502/system/console/status-slingmodels

Custom Injectors

Object getValue(Object adabtable, String name, Type type, AnnotatedElement
                 element, DisposalCallbackRegistry callbackRegistry)

Injectors are OSGI service.

In case of Out-of-the-box injectors don’t cover your requirements, you can create a custom injector.
For this you must implement the org.apache.sling.models.spi.Injector interface & override getValue method.

How Sling Models and HTL meet?

<div data-sly-use.myClass="mysite.myproject.HeaderComponent"> 
      ${ myClass.fullName } 
</div> 

Here is an example of using Sling Model in an HTL template with data-sly-use statement.

Can we pass in parameters?

<div data-sly-use.myClass="${'mysite.myproject.HeaderComponent' @ param1=currentPage,     
   param2='advanced'}"> 
      ${ myClass.fullName } 
</div> 

Here is how you can pass parameters to a Sling Model, be aware that it’s available only if your Sling Model is adaptables from SlingRequest.

Sling Model Exporters

Another feature I want to mention here, is Sling Model Exporters. It’s available since Sling Models version 1.3.0 & with the exporter annotation you can define how your model can be exported as a different Java object or more commonly serialized into a different format such as JSON.

Apache sling provides a Jackson JSON exporter to cover a most common case of exporting sling models as JSON objects for consumption by programmatic web consumers, such as other web services & JavaScript applications.

On this diagram you see that traditional use case of Sling Models which is grayed out on the left & the one with exporters.

Hope you enjoyed this article, I would like to suggest, Kindly watch video below for practical session. In the next part I’ll try to review more details about Sling Model Exporters. Thank you for your attention!