March 29, 2020
Estimated Post Reading Time ~

Deep Dive on Sling Model in AEM 6.3: Part - 2

In our previous blog, we have already learned the basics of sling models. But the magic of sling models is not over. We have more to know.

We have seen injector specific annotations of sling models in Part-1, except for all these specific sling model Injectors we have some more annotations that help in Sling Models Development.

@Inject: This annotation is used to inject a property, resource, request anything. This is a generic annotation, which traverses all the sling model injectors based on service ranking.

@Model(adaptables = Resource.class)
public classTest {
@Inject
String path;

public String getPath() {
return path;
}
}

@Named: If there is a need to change the getter of any attribute like (sling:resourceType, jcr:primaryType) @Named annotation helps to achieve this.
@Model(adaptables = Resource.class)
public class Test {

@Inject @Named("sling:resourceType")
String slingResourceType;

public String getSlingResourceType() {
return slingResourceType;
}
}

@Default: A default value can be provided for Strings or primitive data types. If there is no value of that property, the default value takes place.
@Model(adaptables = Resource.class)
public class Test {

@Inject @Default(values = "/content/test")
String path;

public String getPath() {
return path;
}
}


@Optional and @Required:
In the sling models, by default all the fields supposed to be required. Sometimes there is a need to mark them as optional and required specifications.So injector fields can be annotated with @Optional and @Required.

If a majority of @Injected fields/methods are optional, it is possible to change the default injection strategy by using adding defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL to the @Model annotation:

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

@Inject @Optional
String path;

@Inject @Required
String title;

public String getTitle() {
return title;
}

public String getPath() {
return path;
}
}


@Source: If you are using @Inject annotation and you want to specifically tell the sling engine that which specific injector you want to inject, you can use this annotation. All the specific injectors can also be used with @Source annotations. Using this annotation is equivalent to using injector specific annotation in a different way.

@Model(adaptables = SlingHttpServletRequest.class)
public class Test {

@Inject @Source("script-bindings")
Page currentPage;

public String getPath() {
return currentPage.getPath();
}
}

@Via: SlingHttpServletRequest has more objects than resource. Sometimes there is a need for using two injectors one from request and one from the resource, Then we need to tell annotation explicitly that you are coming via resource.

@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {

// Injects ResourcePath with Via annotation
@ResourcePath(path = "/etc/social") @Via("resource")
Resource resource;

// Injects currentPage from ScriptVariable adaptable to Request
@ScriptVariable
Page currentPage;
}

@PostConstruct: The @PostConstruct annotation can be used to add methods that are invoked upon completion of all injections: This method automatically gets called when a sling model instance is created.

Note: The name of the method doesn’t matter, only it is matters on which method the PostConstruct annotation exists.

@Model(adaptables = SlingHttpServletRequest.class)
public class Test {

@Inject @Source("script-bindings")
Page currentPage;
String path;

@PostConstruct
protected void postMethod() {
path = currentPage.getPath();
}
public String getPath() {
return path;
}
}


@AemObject Annotation by ACS Commons Package

ACS Commons package provides one more injector specific annotation named @AemObject.This annotation provides the support of a lot of objects shown below:

Fig- List of an object in @AemObject annotation provided by ACS Common

This annotation is not the part of sling models, so if sling models itself have all your needed injectors, no need to go for it. But some Objects are not available with sling models like Tagmanager, WorkflowSession, WCMMode, at that time, this annotation can help you. Remember your project must have dependencies of ACS-Commons before using this annotation.

@Model(adaptables = SlingHttpServletRequest.class)
public class TestModel {

// Injects currentPage using ScriptVariable annotation
@AemObject
Page currentPage;

public String getPagePath() {
currentPage.getPath();
}
}


List Injection From Child Resource(Since Sling Models Impl 1.0.6)
+- resource (being adapted)
|
+- content
|
+- subchild1
|
+- subchild

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

@Inject
List<Resource> content;

public int getSize()
{
return content.size();
}
}


Sling Adapter Framework
1.adaptTo: Apache Sling provides a way to adapt Sling related classes to our domain classes. The Resource and ResourceResolver interface provides the adaptTo method, which adapts the objects to other classes.

With the adaptTo API, we can convert the Sling-related objects to our Model objects by using the AdapterFactory classes.
Test model = resource.adaptTo(Test .class)

As with other AdapterFactories, if the adaptation can't be made for any reason, adaptTo() returns null.

2.ModelFactory (Since1.2.0): Since Sling Models 1.2.0 there is another way of instantiating models. The OSGi service ModelFactory provides a method for instantiating a model that throws exceptions. There is no need for null checks and it is easier to see why sling model instantiation is failed. ModelFactory API provides a lot of methods, which can be efficiently used.

public class ModelServlet extends SlingSafeMethodsServlet {

@Reference
ModelFactory modelFactory;

@Override
protected void doGet(final SlingHttpServletRequest req,final SlingHttpServletResponse resp) throws ServletException, IOException {

Resource resource = req.getResourceResolver().getResource("/content/community-components/en/tagcloud/jcr:content");

Test test = modelFactory.createModel(resource, Test.class);
resp.getWriter().println(test.getResourceType());
resp.getWriter().println(modelFactory.canCreateFromAdaptable(resource, Test.class));
resp.getWriter().println(modelFactory.canCreateFromAdaptable(req, Test.class));
}
}

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

@Inject @Named("sling:resourceType")
String resourceType;

public String getResourceType()
{
return resourceType;
}
}


By aem4beginner

No comments:

Post a Comment

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