This conversation has been locked due to inactivity. Please create a new post.
This conversation has been locked due to inactivity. Please create a new post.
Hi Community and Friends,
I'm taking a look at the Sling Models Injections using the Constructor, and I am wondering who has experience with this feature?
@Model(adaptables=Resource.class)
public class MyModel {
public MyModel(@Named("propertyName") String propertyName) {
// constructor code
}
}
Documentation: https://sling.apache.org/documentation/bundles/models.html#basic-usage
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @SupportMember,
Good question! I'll answer as best I can but I won't pretend to be a Sling expert 😉
So firstly, if you wanted to use constructor injection rather than field injection, you can do it quite easily using much of the same syntax. To illustrate my point, let's have a look at the HelloWorldModel generated by the latest AEM Archetype 23 (simplified a bit to be less verbose):
@Model(adaptables = Resource.class)
public class HelloWorldModel {
@ValueMapValue(name = PROPERTY_RESOURCE_TYPE, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = "No resourceType")
protected String resourceType;
@SlingObject
private Resource currentResource;
@SlingObject
private ResourceResolver resourceResolver;
@Getter
private String message;
@PostConstruct
protected void init() {
final PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
final String currentPagePath = Optional.ofNullable(pageManager)
.map(pm -> pm.getContainingPage(currentResource))
.map(Page::getPath).orElse("");
message = "\tHello World!\n"
+ "\tResource type is: " + resourceType + "\n"
+ "\tCurrent page is: " + currentPagePath + "\n";
}
}
As we can see, it uses field injection. Now let's copy this component and create a version which uses constructor injection:
@Model(adaptables = Resource.class)
public class HelloWorldModelConstructorInjection {
protected String resourceType;
private final Resource currentResource;
private final ResourceResolver resourceResolver;
@Getter
private String message;
@Inject
public HelloWorldModelConstructorInjection(@ValueMapValue(name = PROPERTY_RESOURCE_TYPE, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = "No resourceType") final String resourceType,
@SlingObject final Resource currentResource,
@SlingObject final ResourceResolver resourceResolver) {
this.resourceType = resourceType;
this.currentResource = currentResource;
this.resourceResolver = resourceResolver;
}
@PostConstruct
protected void init() {
final PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
final String currentPagePath = Optional.ofNullable(pageManager)
.map(pm -> pm.getContainingPage(currentResource))
.map(Page::getPath).orElse("");
message = "\tHello World!\n"
+ "\tResource type is: " + resourceType + "\n"
+ "\tCurrent page is: " + currentPagePath + "\n";
}
}
So basically you just:
We can test this to make sure it works. Here is are the components side by side:
Works like a charm 🙂
Now regarding the actual usefulness of this feature: as a general rule, constructor is preferable to field injection for two main reasons:
However, when using Sling models in an AEM context I think there is a trade-off to be made between observing best-practices and writing readable, maintanable code.
Personally, I use field injection for models.
Hope that all makes sense 🙂
Hi @SupportMember,
Good question! I'll answer as best I can but I won't pretend to be a Sling expert 😉
So firstly, if you wanted to use constructor injection rather than field injection, you can do it quite easily using much of the same syntax. To illustrate my point, let's have a look at the HelloWorldModel generated by the latest AEM Archetype 23 (simplified a bit to be less verbose):
@Model(adaptables = Resource.class)
public class HelloWorldModel {
@ValueMapValue(name = PROPERTY_RESOURCE_TYPE, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = "No resourceType")
protected String resourceType;
@SlingObject
private Resource currentResource;
@SlingObject
private ResourceResolver resourceResolver;
@Getter
private String message;
@PostConstruct
protected void init() {
final PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
final String currentPagePath = Optional.ofNullable(pageManager)
.map(pm -> pm.getContainingPage(currentResource))
.map(Page::getPath).orElse("");
message = "\tHello World!\n"
+ "\tResource type is: " + resourceType + "\n"
+ "\tCurrent page is: " + currentPagePath + "\n";
}
}
As we can see, it uses field injection. Now let's copy this component and create a version which uses constructor injection:
@Model(adaptables = Resource.class)
public class HelloWorldModelConstructorInjection {
protected String resourceType;
private final Resource currentResource;
private final ResourceResolver resourceResolver;
@Getter
private String message;
@Inject
public HelloWorldModelConstructorInjection(@ValueMapValue(name = PROPERTY_RESOURCE_TYPE, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = "No resourceType") final String resourceType,
@SlingObject final Resource currentResource,
@SlingObject final ResourceResolver resourceResolver) {
this.resourceType = resourceType;
this.currentResource = currentResource;
this.resourceResolver = resourceResolver;
}
@PostConstruct
protected void init() {
final PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
final String currentPagePath = Optional.ofNullable(pageManager)
.map(pm -> pm.getContainingPage(currentResource))
.map(Page::getPath).orElse("");
message = "\tHello World!\n"
+ "\tResource type is: " + resourceType + "\n"
+ "\tCurrent page is: " + currentPagePath + "\n";
}
}
So basically you just:
We can test this to make sure it works. Here is are the components side by side:
Works like a charm 🙂
Now regarding the actual usefulness of this feature: as a general rule, constructor is preferable to field injection for two main reasons:
However, when using Sling models in an AEM context I think there is a trade-off to be made between observing best-practices and writing readable, maintanable code.
Personally, I use field injection for models.
Hope that all makes sense 🙂
Views
Likes
Replies
Views
Likes
Replies