Hello Community - I am trying to obtain the resource from the existing resource path using Sling model (Not servlet). I am able to get the properties (buttonlabel) values for the component path.
I need some additional properties from the jcr:content of the given path. When I pass the given path to the resource resolver, it throws some exception. could someone please help here?
@Model(adaptables = { Resource.class,SlingHttpServletRequest.class})
public class ResourcePathModel {
private String buttonlabel;
private Resource jcrResource;
@inject
@source("sling-object")
private ResourceResolver resourceResolver;
public ResourcePathModel(Resource resource) {
ValueMap resVal = resource.getValueMap(); //This is the resource.getPath() - /content/we-retail/blog/en/jcr:content/root/container/content/hero_image
this.buttonlabel = resVal.get("buttonlabel", String.class); //Here I am able to retrieve the values with no issues.
try {
jcrPath = "/content/weretail/blog/en/jcr:content";
jcrResource = resourceResolver.getResource(jcrPath); //Having issues and getting exception here.
if (jcrResource != null) {
jcrNode = jcrResource.adaptTo(Node.class);
jcrTitle = jcrNode.getProperty("jcr:title").getString();
}
} catch (RepositoryException e) {
LOG.info("RepositoryException " + e);
}
}
}
Exception:
org.apache.sling.models.factory.MissingElementsException: Could not inject all required fields into class com.uhg.uhcmr.aem.core.models.ActiveElementNodeModel
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:765)
at org.apache.sling.models.impl.ModelAdapterFactory.internalCreateModel(ModelAdapterFactory.java:448)
Solved! Go to Solution.
Views
Replies
Total Likes
@v1101, your code looks accurate,
@ScriptVariable
private ResourceResolver resolver;
Take a look at this Sling Models Reference Guide, its a good example of how you can inject AEM objects via AEM Sling Model Injectors, https://sourcedcode.com/blog/aem/aem-sling-model-injectors-annotations-reference-guide
Also, working Sling Model Example (simplified way): Note, you can get the resource's value map using the Sling Model Injectors, @ValueMapValue
package uk.co.whitbread.shared.bundle.slingmodels.desktop.components.hdhoteldetails.topsection;
import com.day.cq.wcm.api.Page;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import javax.annotation.PostConstruct;
@Getter
@Model(adaptables = {SlingHttpServletRequest.class, Resource.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ResourcePathModel {
@ScriptVariable
private ResourceResolver resolver;
@ScriptVariable
private Page currentPage;
@ValueMapValue
private String myComponentCustomProperty;
@Getter
private String exportTitle;
@PostConstruct
public void init() {
if (StringUtils.isNotEmpty(myComponentCustomProperty)) {
Resource resource = resolver.getResource(myComponentCustomProperty);
if (resource != null) {
// DO LOGIC HERE
exportTitle = "something";
} else {
exportTitle = currentPage.getTitle();
}
}
}
}
We can use @SlingObject to get ResourceResolver in slingmodels.
@SlingObject
private ResourceResolver resolver;
use this resolver to get resource.
@PostConstruct @Override protected void init() { Resource resource = resolver.getResource("/your-path"); ValueMap map= resource.getValueMap(); //get properties map.get(JcrConstants.JCR_TITLE,String.class);
//your code... }
Views
Replies
Total Likes
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.jsoup.helper.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.stream.Stream;
@Model(adaptables = { Resource.class,SlingHttpServletRequest.class})
public class ResourcePathModel {
private String buttonlabel;
private Resource jcrResource;
private String jcrPath;
@inject
private ResourceResolver resourceResolver;
public ResourcePathModel (Resource resource) {
this.buttonlabel = childResources.get("buttonlabel", String.class);
ValueMap resVal = resource.getValueMap();
this.buttonlabel = resVal.get("buttonlabel", String.class); //Here I am able to retrieve the values with no issues.
try {
jcrPath = "/content/weretail/blog/en/jcr:content";
jcrResource = resourceResolver.getResource(jcrPath); //Having issues and getting exception here.
if (jcrResource != null) {
jcrNode = jcrResource.adaptTo(Node.class);
jcrTitle = jcrNode.getProperty("jcr:title").getString();
}
}catch (RepositoryException e) {
LOG.info("RepositoryException " + e);
}
}
}
Hi @v1101 ,
Please try @SlingObject to get resource resolver.
please follow below link for reference .
https://sling.apache.org/documentation/bundles/models.html
Thanks,
Sandeep.
Hi @v1101
You don't have a default Constructor (Constructor without any parameters) because of which your Model is failing to instantiate. As you are adding your own Constructor Java Compiler will not provide the default one, you must add explicitly. Add below two line it should work.
public ResourcePathModel() {
}
AG
I don't know if you have any specific reason to get the resourceResovler's stand alone object. If nothing special, you can get resourceResolver and Resource from request as well as you already have servletRequest adaptable in your model. there will be advantage like you not need to close the resourceResolver explicitly.
if Not you can use @SlingObject annotation to get the resolver as your model is adaptables to slingRequest.
OR you can also get currentPage with @inject annotation to get the current page and its jcr node.
Don't stick to only one solution to your problem as there are multiple option available to hande it.
And if possible use injection strategy like
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL that will make your code more flexible.
hope this will help.
Umesh Thakur
@v1101, your code looks accurate,
@ScriptVariable
private ResourceResolver resolver;
Take a look at this Sling Models Reference Guide, its a good example of how you can inject AEM objects via AEM Sling Model Injectors, https://sourcedcode.com/blog/aem/aem-sling-model-injectors-annotations-reference-guide
Also, working Sling Model Example (simplified way): Note, you can get the resource's value map using the Sling Model Injectors, @ValueMapValue
package uk.co.whitbread.shared.bundle.slingmodels.desktop.components.hdhoteldetails.topsection;
import com.day.cq.wcm.api.Page;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import javax.annotation.PostConstruct;
@Getter
@Model(adaptables = {SlingHttpServletRequest.class, Resource.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ResourcePathModel {
@ScriptVariable
private ResourceResolver resolver;
@ScriptVariable
private Page currentPage;
@ValueMapValue
private String myComponentCustomProperty;
@Getter
private String exportTitle;
@PostConstruct
public void init() {
if (StringUtils.isNotEmpty(myComponentCustomProperty)) {
Resource resource = resolver.getResource(myComponentCustomProperty);
if (resource != null) {
// DO LOGIC HERE
exportTitle = "something";
} else {
exportTitle = currentPage.getTitle();
}
}
}
}
Hi @v1101
You can directly access current page properties in Sling Models as mentioned below.
@ScriptVariable
private ValueMap pageProperties;
pageProperties.get(JcrConstants.JCR_TITLE);
Could you please try to get page property by injecting page object using below:
@ScriptVariable private Page currentPage;
and try to add default injection policy as well
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
---------------------------
Note : just FYI
the @inject may not work because of multiple type of adaptable used. If you want to use only @inject annotations then you have to inject using @Via.
Here logic is written in Constructor, there is no default Constructor or Constructor injection. Adding default Constructor or Constructor injection should work here right?
I think Constructor here is executing before the Injection is completed for the properties, hence no resource resolver is being injected. That's where @PostConstruct annotated method is useful when we want to utilize the injected objects in the processing.
Views
Replies
Total Likes
Views
Like
Replies
Views
Likes
Replies
Views
Likes
Replies