taglib prefix=”sling” to Sightly and Sling Model Non-JSP & Non-JSTL implementation

In the past, AEM developers would heavily focus on building AEM components with Java Server Pages (JSPs) & JavaServer Pages Standard Tag Libraries (JSTLs).

There are special JSTLs for AEM JSP components to speed up the development. One popular JSTL is called the Sling Taglib. The Sling Taglib is popular when it comes to writing AEM JSP components which provide the AEM component with the ability to invoke JSP scripts, including Resources and interact with the Sling Repository, all with JSP tags and Expression Language (EL) functions.

This is all great but JSP’s are becoming less common for writing AEM components as Sightly has become more mainstream and best practice. That being said, these JSPs are legacy and needs to be upgraded.

One common task for AEM developers is to upgrade JSP components to Sightly components.

The purpose of this article is to show AEM developers how to start to convert Sling Taglib business logic to Sightly and Sling Model logic, Non-JSP & Non-JSTL implementation.
1
2
Target TagLib:
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling" %>
In this article, we will step through some examples on how to convert Sling Taglib’s Expression Language Functions to Sightly and/or Sling Models logic.

Note: While writing AEM Sightly components, AEM global objects are available and should have most of the AEM’s core JSTL functionalities.

Quick Links

  1. adaptTo()
  2. encode()
  3. findResources()
  4. getAbsoluteParent()
  5. getParents()
  6. getRelativeResource()
  7. getResource()
  8. getValue()
  9. getResource()
  10. hasChildren()
  11. listChildren()

1. adaptTo() to Sling Model & Sightly

Adapts an Adaptable to another class.

Returns: java.lang.Object
Accepts:

  • org.apache.sling.api.adapter.Adaptable – The object to adapt
  • java.lang.String – The name of the class to which to adapt the adaptable

Since: 1.3
JSP: Sling Tablib example usage:

1
2
3
4
<c:set var="valueMap" value="${sling:adaptTo(resource,'org.apache.sling.api.resource.ValueMap')}" />
<c:set var="page" value="${sling:adaptTo(resource,'com.day.cq.wcm.api.Page')}" />
${valueMap}
${page}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
5
<div class="cmp-examplemodel"
   data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    ${examplemodel.valueMap}
    ${examplemodel.page}
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.sourcedcode.aem.core.models;

import com.day.cq.wcm.api.Page;
import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;

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

    @Getter
    private ValueMap valueMap;

    @Getter
    private Page page;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("resource") final Resource resource) {
        valueMap = resource.adaptTo(ValueMap.class); // example here
        page = resource.adaptTo(Page.class);
    }
}

2. encode() to Sling Model & Sightly

Writes properly Cross-Site Scripting (XSS) encoded text to the response using the OWASP ESAPI. Supports a number of encoding modes.

Returns: java.util.String – An encoded text
Accepts:

  • java.lang.String – The text to encode
  • java.lang.String – The encoding mode, one of HTML, HTML_ATTR, XML, XML_ATTR, JS

Since: 1.4
JSP: Sling Tablib example usage:

1
${sling:encode('<script>alert("Bad Stuff!");</script>','HTML')}
Non-JSP & Non-JSTL implementation

Sightly:

1
${'<script>alert("Bad Stuff!");</script>' @ context='html'}

3. findResources() to Sling Model & Sightly

Searches for resources using the given query formulated in the given language.

Returns: java.util.Iterator – An Iterator of Resource objects matching the query.
Accepts:

  • org.apache.sling.api.resource.ResourceResolver – The Resource Resolver to use for the query.
  • java.lang.String – The query string to use to find the resources.
  • java.lang.String – The language in which the query is formulated.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
3
<c:forEach var="resourceItem" items="${sling:findResources(resourceResolver,'/jcr:root//*[jcr:contains(., 'Sling')] order by @jcr:score','xpath')">
    <li>${resourceItem.path}</li>
</c:forEach>
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
5
6
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <ul data-sly-list.resourceItem="${examplemodel.resources}">
        <li>${resourceItem.name}</li>
    </ul>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.sourcedcode.aem.core.models;

import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;

import javax.inject.Inject;
import javax.inject.Named;
import javax.jcr.query.Query;
import java.util.Iterator;

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

    @Getter
    private Iterator<Resource> resources;

    @Inject
    protected void ExampleModel(@SlingObject @Named("resourceResolver") final ResourceResolver resolver) {
        resources = resolver
                .findResources("/jcr:root//*[jcr:contains(., 'Sling')] order by @jcr:score",
                        Query.XPATH);
        // Query.XPATH depricated, recommended to use Query.JCR_SQL2
//        resources = resolver
//                .findResources("SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE([/content/sourcedcode])",
//                        Query.JCR_SQL2);
    }
}

4. getAbsoluteParent() to Sling Model & Sightly

Method for retrieving an absolute parent resource.

Returns: org.apache.sling.api.resource.Resource – The parent resource at the specified level
Accepts:

  • org.apache.sling.api.resource.Resource – The current resource
  • java.lang.String – The absolute level for the parent resource to retrieve

Since: Bundle 2.3.0
JSP: Sling Tablib example usage:

1
2
<c:set var="absoluteParentResource" value="${sling:getAbsoluteParent(resource,'2')}" />
${absoluteParentResource.title}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <h1>${examplemodel.absoluteParentResource.title}</h1>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.sourcedcode.aem.core.models;

import com.day.cq.wcm.api.Page;
import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;

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

    @Getter
    private Page absoluteParentResource;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("currentPage") final com.day.cq.wcm.api.Page currentPage) {
        absoluteParentResource = currentPage.getAbsoluteParent(2);
    }
}

5. getParents() to Sling Model & Sightly

Function for retrieving all of the parent resources of a specified resource, returning them in hierarchy order.

Returns: java.lang.Iterator – an iterator of the parent resources in order
Accepts:

  • org.apache.sling.api.resource.Resource – The current resource for which to retrieve the parents
  • java.lang.String – The depth at which to start, for example given a path of: /content/page1/page2/page3 and a start depth of 3, the parents page2/page3 would be returned

Since: Bundle 2.3.0
JSP: Sling Tablib example usage:

1
2
3
4
<c:set var="parentResources" value="${sling:getParents(resource,'2')}" />
<c:forEach var="parentResourceItem" items="${parentResources}">
    <div>${parentResourceItem.path}</div>
</c:forEach>
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
5
6
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <ul data-sly-list.parentResourceItem="${examplemodel.parentResources}">
        <li>${parentResourceItem.name}</li>
    </ul>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.sourcedcode.aem.core.models;

import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.Iterator;

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

    @Getter
    private Iterator<Resource> parentResources;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("resource") final Resource resource) {
        parentResources = getParents(resource, 2);
    }

    // no Sling API found, this is custom code
    private Iterator<Resource> getParents(Resource resource, int depth) {
        Resource currentResource = resource;
        for (int i = 0; i < depth; i++) {
            if (currentResource.getParent() != null) {
                currentResource = currentResource.getParent();
            }
        }
        return resource.listChildren();
    }
}

6. getRelativeResource() to Sling Model & Sightly

Gets the resource at the relative path to the provided resource.

Returns: org.apache.sling.api.resource.Resource – The resource at the relative path.
Accepts:

  • org.apache.sling.api.resource.Resource – The resource relative to which to find the path.
  • java.lang.String – The relative path at which to find the resource.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
<c:set var="myResource" value="${sling:getRelativeResource(resource,'jcr:content')}" />
${myResource.name}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <p>${examplemodel.myResource.name}</p>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.sourcedcode.aem.core.models;

import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;

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

    @Getter
    private Resource myResource;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("resource") final Resource resource) {
        myResource = resource.getChild("jcr:content");
    }
}

7. getResource() to Sling Model & Sightly

Method allow for the retrieval of resources.

Returns: org.apache.sling.api.resource.Resource – The resource at the path.
Accepts:

  • org.apache.sling.api.resource.ResourceResolver – The current resource resolver.
  • java.lang.String – The path at which to find the resource.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
<c:set var="myResource" value="${sling:getResource(resourceResolver,'/content')}" />
${myResource.name}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <p>${examplemodel.myResource.name}</p>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.sourcedcode.aem.core.models;

import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;

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

    @Getter
    private Resource myResource;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("resolver") final ResourceResolver resolver) {
        myResource = resolver.getResource("/content");
    }
}

8. getValue() to Sling Model & Sightly

Gets the value of the specified key from the ValueMap and either coerses the value into the specified type or uses the specified type as a default depending on the parameter passed in.

If the third parameter is a class, the resulting value will be coersed into the class, otherwise, the third parameter is used as the default when retrieving the value from the ValueMap.

Returns: java.lang.Object – The value.
Accepts:

  • org.apache.sling.api.resource.ValueMap – The ValueMap from which to retrieve the value.
  • java.lang.String – The key for the value to retrieve
  • java.lang.Object – Either the default value or the class to which to coerce the value.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
<c:set var="myResourceTitle" value="${sling:getValue(properties,'jcr:title',resource.name)}" />
${myResourceTitle}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
<div class="cmp-examplemodel">
    ${properties.jcr:title}
</div>

9. getResource() to Sling Model & Sightly

Method allow for the retrieval of resources.

Returns: org.apache.sling.api.resource.Resource – The resource at the path.
Accepts:

  • org.apache.sling.api.resource.ResourceResolver – The current resource resolver.
  • java.lang.String – The path at which to find the resource.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
<c:set var="myResource" value="${sling:getResource(resourceResolver,'/content')}" />
${myResource.name}
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
<div class="cmp-examplemodel"
    data-sly-use.examplemodel="com.sourcedcode.aem.core.models.ExampleModel">
    <p>${examplemodel.myResource.name}</p>
</div>

Sling Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.sourcedcode.aem.core.models;

import lombok.Getter;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import javax.inject.Inject;
import javax.inject.Named;

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

    @Getter
    private Resource myResource;

    @Inject
    protected void ExampleModel(@ScriptVariable @Named("resolver") final ResourceResolver resolver) {
        myResource = resolver.getResource("/content");
    }
}

10. hasChildren() to Sling Model & Sightly

Return true if the specified resource has child resources.

Returns: java.lang.Boolean – True if there are child resource of the specified resource
Accepts:

  • org.apache.sling.api.resource.Resource – The resource of which to check for children.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
3
<c:if test="${sling:hasChildren(resource)">
    <h1>This resource has children</h1>
</c:if>
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
5
<div class="cmp-examplemodel">
    <div data-sly-test="${resource.hasChildren}">
        <h1>This resource has children</h1>
    </div>
</div>

11. listChildren() to Sling Model & Sightly

Method for allowing the invocation of the Sling Resource listChildren method.

Returns: java.util.Iterator – The children of the resource.
Accepts:

  • org.apache.sling.api.resource.Resource – The resource of which to list the children.

Since: 1.3
JSP: Sling Tablib example usage:

1
2
3
<c:forEach var="child" items="${sling:listChildren(resource)">
    <li>${child.path}</li>
</c:forEach>
Non-JSP & Non-JSTL implementation

Sightly:

1
2
3
4
5
<div class="cmp-examplemodel">
    <ul data-sly-list.child="${resource.listChildren}">
        <li>${child.path}</li>
    </ul>
</div>

Hello, I am an enthusiastic Adobe Community Advisor and a seasoned Lead AEM Developer. I am currently serving as an AEM Technical Lead at MNPDigital.ca, bringing over a decade of extensive web engineering experience and more than eight years of practical AEM experience to the table. My goal is to give back to the AEM Full Stack Development community by sharing my wealth of knowledge with others. You can connect with me on LinkedIn.

Leave a Reply

Your email address will not be published. Required fields are marked *


Back To Top