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>

Was this post helpful?

Hello, I am an Adobe AEM MVP & a certified Lead AEM Developer who is currently working as a Senior AEM Full Stack Developer at Whitbread, UK, London. I have 10 years of overall web engineering experience and 6 years of AEM experience in practice. I hope to give back to the AEM Full Stack Development community by sharing my knowledge with the world.

Leave a Reply

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

Back To Top