Usage of @Via in sling models

Avatar

Avatar

Nitiks25

Avatar

Nitiks25

Nitiks25

10-10-2017

I understand from the documentation, that @Via is used to inject objects not available through the adaptable mapped to the model

In that case, if my adaptable is Resource.class and I have to inject SlingHttpServletRequset or SlingHttpServletResponse. I will have to use @Inject @Via to fetch it from SlingHttpServletRequest adaptable?

In that case, what is the parameter I have to pass to @Via?

In case of resource, it will be @Via ("resource") - what will it be for slingRequest?

Accepted Solutions (1)

Accepted Solutions (1)

Avatar

Avatar

Veena_Vikram

MVP

Avatar

Veena_Vikram

MVP

Veena_Vikram
MVP

11-10-2017

Nitik,

  Let me try to explain you what I understand here . Let us take the simple example from what documentation Scott has shared

  - So this says ; when the model's adaptable is SlingHttpServletRequest , then when you try to inject getPropertyName() ; it will be return the property via resource method of the SlingHttpServletRequest object "request" like the below

request.getResource().getValueMap().get("propertyName", String.class)

That said , if you check the API SlingHttpServletRequest (Apache Sling Aggregate 5-incubator API)  you can understand that a resource can be fetched from a request , but the vice versa is not possible .

    So basically that means inject the value via resource API in SlingHttpServletRequest API.

  I am not aware of a way to get a request object from a resource and hence I don't believe something like below is even possible

@Model(adaptables=Resource.class)

public class MyModel

    @Inject

    @Via("request")

    private String someObj;

}

For further reading the below section explains what all standard types are provided via while and how it is implemented

Apache Sling :: Sling Models

The other thing you can do is to adapt the SlingHttpServletRequest and get the resource from it

@Model(adaptables = SlingHttpServletRequest.class)

public class MyModel {

  

     @Inject

     SlingHttpServletRequest request;

     @PostConstruct

     protected void init() {

         Resource resource = request.getResource() ;

     }

}

Answers (24)

Answers (24)

Avatar

Avatar

AEM_Forums

Avatar

AEM_Forums

AEM_Forums

17-07-2018

Yes, I tested this article and it works!! Below is the screenshot.

Title.PNG

dialog.PNG

Hope this helps!!

Thanks,

Ratna Kumar.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

17-07-2018

The doc example is wrong - the new HELPX artilce - follow it to learn how to extend core components - the Java part. You have to extend it as shown in the artilce. We are going to fix the example in the docs too to point to this new article. Ratna Kumar is currently testing this article.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

I got it compiling with @Via

1st - i created a new Maven 13 Archetype project following this article: Creating an Adobe Experience Manager 6.4 Project using Adobe Maven Archetype 13

2nd added the new class to this project;  (NEVER ADD  A CLASS TO THE CORE COMPONENT PROJECT taken from Github). Always extend from a new AEM Java project. Here is full example:

package com.adobe.community.core.models;

import org.apache.sling.models.annotations.injectorspecific.Self;

import org.apache.sling.models.annotations.Via;

import org.apache.sling.api.resource.Resource;

import org.apache.sling.models.annotations.Default;

import org.apache.sling.models.annotations.Model;

import org.apache.sling.settings.SlingSettingsService;

import org.apache.sling.api.SlingHttpServletRequest;

import org.apache.sling.models.annotations.via.ResourceSuperType;

import com.adobe.cq.wcm.core.components.models.Breadcrumb;

@Model(adaptables = SlingHttpServletRequest.class,

       adapters = Breadcrumb.class,

       resourceType = "my-site/components/breadcrumb")

public class MyCustomBreadcrumbImpl implements Breadcrumb {

    /* ... */

    // get the default implementation for delegating

@Self @Via(value="core/wcm/components/breadcrumb/v2/breadcrumb", type=ResourceSuperType.class)

    private Breadcrumb delegate;

}

See:

M445.png

3rd -add Core Components in POM

<dependency>

        <artifactId>core.wcm.components.core</artifactId>

        <version>2.0.4</version>

        <groupId>com.adobe.cq</groupId>

        <scope>provided</scope>

        </dependency>

(plus the UBER AEM JAR and others discussed in above article)

Finally -- if anyone wants to know more about the @Via annotation - see this Javadoc here - Apache Sling 9 API

Avatar

Avatar

rajeevy89244319

Avatar

rajeevy89244319

rajeevy89244319

17-07-2018

Thanks Sam.

In helpx example, we are just using core title contract and then implementing the logic. In order to extend existing title implementation, what is recommended approach? Should we extended core implementation class or should we use @Via.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

17-07-2018

For anyone reading this thread and want to know how to extend a Core Component - see this HELPX article -- Extending Adobe Experience Manager Core Components

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

Here is a much better example to extend a Core Component - we will make a HELPX article -- use this to extend the Title COMPONENT. Notice here - they are not even using @Via

package com.adobe.community.core.models;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;

import org.apache.sling.api.SlingHttpServletRequest;

import org.apache.sling.models.annotations.Model;

import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;

import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;

import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

import com.adobe.cq.wcm.core.components.models.Title;

import com.day.cq.commons.jcr.JcrConstants;

import com.day.cq.wcm.api.Page;

import com.day.cq.wcm.api.designer.Style;

@Model(resourceType = "/apps/ExtendCore/components/content/title",

    adaptables = SlingHttpServletRequest.class,

    adapters = Title.class)

public class MyCustomTitleImpl implements Title {

    @ScriptVariable

    private Page currentPage;

    @ScriptVariable

    private Style currentStyle;

    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = JcrConstants.JCR_TITLE)

    private String title;

    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)

    private String type;

    /**

     * The {@link Heading} object for the type of this title.

     */

    private Heading heading;

    @PostConstruct

    private void initModel() {

        if (StringUtils.isBlank(title)) {

            title = StringUtils.defaultIfEmpty(currentPage.getPageTitle(), currentPage.getTitle());

        }

        if (heading == null) {

            heading = Heading.getHeading(type);

            if (heading == null) {

                heading = Heading.getHeading(currentStyle.get(PN_DESIGN_DEFAULT_TYPE, String.class));

            }

        }

    }

    @Override

    public String getText() {

        return "My Project - " + title;

    }

    @Override

    public String getType() {

        if (heading != null) {

            return heading.getElement();

        }

        return null;

    }

    private enum Heading {

        H1("h1"),

        H2("h2"),

        H3("h3"),

        H4("h4"),

        H5("h5"),

        H6("h6");

        private String element;

        Heading(String element) {

            this.element = element;

        }

        private static Heading getHeading(String value) {

            for (Heading heading : values()) {

                if (StringUtils.equalsIgnoreCase(heading.element, value)) {

                    return heading;

                }

            }

            return null;

        }

        public String getElement() {

            return element;

        }

    }

}

Avatar

Avatar

rajeevy89244319

Avatar

rajeevy89244319

rajeevy89244319

16-07-2018

Thanks Sam. I see.. you changed attribute resourceType to value for @via.. So documentation needs to be updated for correct attribute,

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

Yes - doc example looks wrong for sure. I am workign on this one. I am talking to the consulting team to see if we have a good KB articles on this as well. We will log a bug on the docs as @Via does not support what is shown in the docs.

Avatar

Avatar

rajeevy89244319

Avatar

rajeevy89244319

rajeevy89244319

16-07-2018

I have tried with imports but getting error. For @Via, only type and value attributes are allowed. resourceType is invalid attribute. Not sure if it has to dependency bundle version mismatch.

1529298_pastedImage_0.png

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

Problem with this code example in the AEM Docs is its missing import statements. I am adding them and will post back the version that compiles.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

OK -- I am going to try to do this.

Avatar

Avatar

rajeevy89244319

Avatar

rajeevy89244319

rajeevy89244319

16-07-2018

It is in customizing the logic section on Customizing Core Components

Below is code snippet provided:

package com.mysite.components.models;

@Model(adaptables = SlingHttpServletRequest.class,

       adapters = Breadcrumb.class,

       resourceType = "my-site/components/breadcrumb")

public class MyCustomBreadcrumbImpl implements Breadcrumb {

    /* ... */

    // get the default implementation for delegating

    @Self @Via(resourceType="core/wcm/components/breadcrumb/v2/breadcrumb", type=ResourceSuperType.class)

    private Breadcrumb delegate;

}

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

16-07-2018

Where does it state that when customizing Core Components - you can use @Via annotation. I want to follow along.

Avatar

Avatar

rajeevy89244319

Avatar

rajeevy89244319

rajeevy89244319

16-07-2018

I am trying to follow documentation on Customizing Core Components

// get the default implementation for delegating

@Self @Via(resourceType="core/wcm/components/breadcrumb/v2/breadcrumb", type=ResourceSuperType.class)

When I am trying to use resourceType with @Via, I am getting compilation error saying that resourceType attribute is not supported for @via annotation. Has anyone tried this and can assist me with correct dependencies to use this.

Thanks,

Rajeev

Avatar

Avatar

Veena_Vikram

MVP

Avatar

Veena_Vikram

MVP

Veena_Vikram
MVP

13-10-2017

I would request some expert advice Jörg HohFeike Visser

Avatar

Avatar

Nitiks25

Avatar

Nitiks25

Nitiks25

13-10-2017

I have tried @slingObject too but intermittently it returns a null response. And from what I understand from the documentation that is also not supposed to work since adaptable is not request. But weirdly @inject is working fine.

Avatar

Avatar

Veena_Vikram

MVP

Avatar

Veena_Vikram

MVP

Veena_Vikram
MVP

13-10-2017

Yes Nitik. I am wondering how that can be possible. Because you cannot inject a SlingHttpResponse object to a class which is adapted as Resource. The documentations says as below.

@Inject : marks a field or method as injectable - If this is to be believed then your class (which is adapted as a Resource) cannot inject a response object.

I am not sure if anything here make sense at all SlingObject (Apache Sling 8 API)  .

Avatar

Avatar

Nitiks25

Avatar

Nitiks25

Nitiks25

13-10-2017

Thanks a lot Veena,

yes, if you could let me know that will help a lot

because as per the documentation injecting response object using @ inject when the adaptable is resource is not suppose to work but it is still working.

Avatar

Avatar

digitalect-expe

Avatar

digitalect-expe

digitalect-expe

12-10-2017

for sling request it will be:

@Self

SlingHttpServletRequest  request;

Avatar

Avatar

Veena_Vikram

MVP

Avatar

Veena_Vikram

MVP

Veena_Vikram
MVP

12-10-2017

I have not tried injecting a response object . but I will surely give it a try and get back to you.

Avatar

Avatar

BrijeshYadav

Avatar

BrijeshYadav

BrijeshYadav

12-10-2017

Hi,

I think you should use @SlingObject injector. like below
@Model(adaptables = Resource.class)

public class ResourceExampleModel {

  @SlingObject

   private SlingHttpServletRequest request;

}

As par the documentation also @SlingObject injects commonly used sling objects if the field matches with the class: request, response, resource resolver, current resource, SlingScriptHelper
Apache Sling :: Sling Models

/Brijesh Yadav

Avatar

Avatar

Nitiks25

Avatar

Nitiks25

Nitiks25

11-10-2017

Thanks a lot Veena. Makes sense now. But I want clarification on one thing: I have the model adaptable as Resource. And I have injected slinghttpservletresponse object using just an @Inject i.e.

@Inject

SlingHttpServletResponse response

and a valid response object is being returned. As per documentation, this isn't supposed to happen since response object is only supposed to be available if model is set to sling request as adaptalbe

I'm just wondering, how it is working then?

Avatar

Avatar

Nitiks25

Avatar

Nitiks25

Nitiks25

11-10-2017

Thanks Smacdonald,

From that page it is clear what the Via Type does i.e choose a different adaptable for a particular injection. It's also given an example of how to set Resource as the adaptable for an Injection if the adaptable model is sling request:

@Inject @Via("resource")

     String getPropertyName();

But what if the model level adaptable is 'Resource' and I need to choose request as the adaptable for an Injection? that's not given on that page. Is that even possible? Tried @Inject @Via("request")  and other similar parameters but it doesn't work.

Avatar

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K

Avatar

smacdonald2008

Total Posts

12.7K

Likes

1.4K

Correct Reply

2.3K
smacdonald2008

11-10-2017

This annotation is well explained in this topic:

Apache Sling :: Sling Models

There are some code examples too.