December 28, 2020
Estimated Post Reading Time ~

AEM Sling Model Injectors Annotations Reference Guide

The Apache Sling Model enables injector specific annotations which aggregate the standard annotations for each of the available injectors, 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) that 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. 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.

@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 the name is not set the name is derived from the method/field name.

@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.

@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.

@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 the name is not set the name is derived from the method/field name.

@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 the input parameter:

<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 the 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).

@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.

@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 to 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 to injector specific annotation is used (@SlingObject).

@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 the 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 organized, write less code, and speed up the development process.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.