AEM Sling Model Injectors Annotations Reference Guide

thumbnail

The Apache Sling Model enables injector specific annotations which aggregate the standard annotations for each of the available injector, which are: Script Bindings, Value Map, Resource Path, Child Resources, Request Attributes, OSGI Services, Self, and the Sling Object.

Sure we can invoke injectors by the @inject, followed by the @source annotation (with an injector name) as so, @Inject @Source(“script-bindings”), but invoking such injectors introduces many more lines of code which is tedious and repetitive. Using the @inject annotation freely may cause injector collisions.

Thankfully Apache’s Sling Model library delivered the injector specific annotations!
The injector specific annotations enable us, developers, to write less code, enables stability with injectors to demise injector collisions, and enables better IDE support.

This article will provide examples (used in practice) which will include both ways to invoke injectors in Sling Models, using the @Inject & @Source annotations, and also the Apache Sling Model injector specific annotations approach.


Available Injectors

  1. @ScriptVariable
  2. @ValueMapValue
  3. @ResourcePath
  4. @ChildResource
  5. @RequestAttribute
  6. @OSGiService
  7. @Self
  8. @SlingObject

1. Script Bindings (name=”script-bindings”) Injector

Service Ranking: 1000
Annotation: @ScriptVariable
Description: Injects objects via script variable defined from Sling Bindings; Lookup objects in the script bindings object by name.

As you can see, the example below indicated that there are many ways to inject within the POJO:

Without the injector specific annotations:

  • 1. @Inject @Source(“script-bindings”) @Named(“component”)
  • 2. @Inject @Source(“script-bindings”)

With the injector specific annotations:

  • 3. @ScriptVariable(name = “component”)
  • 4. @ScriptVariable

Note: If the name is not set (using the @Named annotation or name property), then the name is derived from the method/property/variable/field name.

A full list of the scripting variables can be found here.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@Model(adaptables = Resource.class,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("script-bindings") @Named("component")
    // @Inject @Source("script-bindings")
    // @ScriptVariable(name = "component")
    @ScriptVariable
    private Component component;

    // @Inject @Source("script-bindings") @Named("componentContext")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private ComponentContext componentContext;

    // @Inject @Source("script-bindings") @Named("currentDesign")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Design currentDesign;

    // @Inject @Source("script-bindings") @Named("currentNode")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Node currentNode;

    // @Inject @Source("script-bindings") @Named("currentPage")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Page currentPage;

    // @Inject @Source("script-bindings") @Named("currentSession")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private HttpSession currentSession;

    // @Inject @Source("script-bindings") @Named("currentStyle")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Style currentStyle;

    // @Inject @Source("script-bindings") @Named("designer")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Designer designer;

    // @Inject @Source("script-bindings") @Named("editContext")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private EditContext editContext;

    // @Inject @Source("script-bindings") @Named("log")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Logger log;

    // @Inject @Source("script-bindings") @Named("out")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private PrintWriter out;

    // @Inject @Source("script-bindings") @Named("pageManager")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private PageManager pageManager;

    // @Inject @Source("script-bindings") @Named("pageProperties")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private ValueMap pageProperties;

    // @Inject @Source("script-bindings") @Named("reader")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private BufferedReader reader;

    // @Inject @Source("script-bindings") @Named("request")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private SlingHttpServletRequest request;

    // @Inject @Source("script-bindings") @Named("resolver")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private ResourceResolver resolver;

    // @Inject @Source("script-bindings") @Named("resource")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Resource resource;

    // @Inject @Source("script-bindings") @Named("resourceDesign")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Design resourceDesign;

    // @Inject @Source("script-bindings") @Named("resourcePage")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private Page resourcePage;

    // @Inject @Source("script-bindings") @Named("response")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private SlingHttpServletResponse response;

    // @Inject @Source("script-bindings") @Named("sling")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private SlingScriptHelper sling;

    // @Inject @Source("script-bindings") @Named("slyWcmHelper")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private WCMScriptHelper slyWcmHelper;

    // @Inject @Source("script-bindings") @Named("wcmmode")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private SightlyWCMMode wcmmode;

    // @Inject @Source("script-bindings") @Named("xssAPI")
    // @Inject @Source("script-bindings")
    @ScriptVariable
    private XSSAPI xssAPI;
}

2. Value Map (name=”valuemap”) Injector

Service Ranking: 2000
Annotation: @ValueMapValue
Description: Gets a property from a ValueMap by name; If @Via is not set, it will automatically take resource if the adaptable is the SlingHttpServletRequest. If name is not set the name is derived from the method/field name.

1
2
3
4
5
6
7
8
9
10
11
12
@Model(adaptables = SlingHttpServletRequest.class,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("valuemap") @Named("jcr:title")
    @ValueMapValue(name = "jcr:title")
    private String titleText;

    // @Inject @Source("valuemap")
    @ValueMapValue
    private String titleDescription;
}

3. Resource Path (name=”resource-path”) Injector

Service Ranking: 2500
Annotation: @ResourcePath
Description: Injects one or multiple resources. The resource paths are either given by @Path annotations, the element path or paths of the annotation @ResourcePath or by paths given through a resource property being referenced by either @Named or element name of the annotation @ResourcePath.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("resource-path") @Path("/content/sourcedcode/en/home")
    @ResourcePath(path = "/content/sourcedcode/en/home")
    Resource sourcedCodePageResource;

    // @Inject @Source("resource-path") @Path("/content/we-retail/language-masters/en")
    @ResourcePath(name = "/content/we-retail/language-masters/en")
    Resource weRetailPageResource;

    // @Inject @Source("resource-path") @Path(paths = {"/content/sourcedcode/en/home","/content/we-retail/language-masters/en"})
    @ResourcePath(paths = {"/content/sourcedcode/en/home","/content/we-retail/language-masters/en"})
    Resource[]  resources;
}

4. Child Resources (name=”child-resources”) Injector

Service Ranking: 3000
Annotation: @ChildResource
Description: Gets a child resource by name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("child-resources") @Named("links")
    // @ChildResource(name="links")
    @ChildResource
    private Resource links;

    // @Inject @Source("child-resources") @Named("links")
    // @ChildResource(name="links")
    @ChildResource
    private List<Resource> links;

    // @Inject @Source("child-resources") @Named("social")
    // @ChildResource(name="social")
    @ChildResource
    private Resource social;
}

5. Request Attributes (name=”request-attributes”) Injector

Service Ranking: 4000
Annotation: @RequestAttribute
Description: Injects a request attribute by name. If name is not set the name is derived from the method/field name.

1
2
3
4
5
6
7
8
9
10
11
12
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("request-attributes") @Named("social")
    @RequestAttribute(name = "social")
    private String socialParam;

    public String getSocialParam() {
        return socialParam;
    }
}

The example below calls the Sling Model using input parameter:

1
2
3
<div data-sly-use.exampleComponent="${'com.sourcedcode.core.models.ExampleComponent' @ social='facebook'}">
    ${exampleComponent.socialParam}
</div>

6. OSGi Services (name=”osgi-services”) Injector

Service Ranking: 5000
Annotation: @OSGiService
Description: Injects an OSGi service by type; Lookup services based on class name. Since Sling Models Impl 1.2.8 (SLING-5664) the service with the highest service ranking is returned. In case multiple services are returned, they are ordered descending by their service ranking (i.e. the one with the highest ranking first).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("osgi-services")
    @OSGIService
    private SlingSettingsService slingSettingsService;

    // @Inject @Source("osgi-services")
    @OSGiService
    private MyCustomOSGIService myCustomOSGIService;

    // @Inject @Source("osgi-services")
    @OSGiService
    private MyCustomOSGISConfigurationervice myCustomOSGISConfigurationervice;
}

7. Self (name=”self”) Injector

Service Ranking: Integer.MAX_VALUE
Annotation: @Self
Description: Injects the adaptable object itself (if the class of the field matches or is a supertype). If the @Self annotation is present it is tried to adapt the adaptable to the field type.

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
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("self")
    @Self
    private Node node;

    // @Inject @Source("self")
    @Self
    private MyCustomSlingModel myCustomSlingModel;
}

///////
///////
/////// Example below highlights that the @self annotation can minimize the lines of code that needs to be written.
///////
///////
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    @SlingObject
    private Resource currentResource;

    Node node;

    @PostConstruct
    public void init() {
        // adapts the current resource to a node class
        node = currentResource.adaptTo(Node.class);
    }
}

8. Sling Object (name=”sling-object”) Injector

Service Ranking: Integer.MAX_VALUE
Annotation: @SlingObject
Description: Injects commonly used sling objects if the field matches with the class: request, response, resource resolver, current resource, SlingScriptHelper. This works only if the adaptable can get the according information, i.e. all objects are available via SlingHttpServletRequest while ResourceResolver can only resolve the ResourceResolver object and nothing else. A discussion around this limitation can be found at SLING-4083. Also Resources can only be injected if the according injector specific annotation is used (@SlingObject).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Model(adaptables = Resource.class,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ExampleComponent {

    // @Inject @Source("sling-object")
    @SlingObject
    private SlingHttpServletRequest slingHttpServletRequest;

    // @Inject @Source("sling-object")
    @SlingObject
    private SlingHttpServletResponse slingHttpServletResponse;

    // @Inject @Source("sling-object")
    @SlingObject
    private Resource currentResource;

    // @Inject @Source("sling-object")
    @SlingObject
    private ResourceResolver resourceResolver;

}
Note:
If the name is not set (using the @Named annotation or name property), then the name is derived from the method/property/variable/field name. An example for setting the @Named annotation would time you as a developer encounter a clash between the method/property/variable/field name or when developer not wanting to use the scripting variable names as the variables in the POJO.

As you can see, using the Apache Sling Model’s injector specific annotations during implementation will help you stay organised, write less code, and speed up the development process.

Certified AEM Developer who has been working on AEM software developer for the past 5 years.

Leave a Reply

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

Back To Top