2

I am new to SlingModels and the annotations aren't very clear yet. I am currently trying to transform some basic foundation components from AEM 6.2 to using SlingModels instead.

For the image component the foundation JSP uses the SlingHttpServletRequest to set the ImageDoctype. So I tried the following:

@Model(adaptables = {Resource.class})
public class ImageModel {
    @SlingObject
    private SlingHttpServletRequest request;

    @SlingObject
    private Resource resource;
}

But with this the request is null. So I switched to using:

@Model(adaptables = {SlingHttpServletRequest.class})

Which works now for reuqest and resource

JSP Code:

<sling:adaptTo adaptable="${slingRequest}" adaptTo="models.ImageModel" var="m"/>

Is this the right way to do it or is there a way to adapt from the resource ans still be able to inject the request?

Thomas
  • 6,325
  • 4
  • 30
  • 65

3 Answers3

3

You can not do that, because resource is not SlingHttpServletRequest aware. If you need Request in your model make it adaptable from Request.

There was some library which allowed to do that. It used Filter to store current Request in ThreadLocal and then read it from it, but I would not recommend this approach. ThreadLocal is just another global.

rzasap
  • 346
  • 1
  • 6
1
@Model(adaptables =  { SlingHttpServletRequest.class, Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ImageModel {
    @Self 
    private Resource resource;

    @SlingObject
    private ResourceResolver resourceResolver;

    @SlingObject
    SlingHttpServletRequest slingRequest;
}
Anuraj
  • 2,551
  • 21
  • 26
  • You adapt always from one class. In case you adapt from request, you have the resource too via the getResource(). And in case you adopt from resource the slingRequest object will be null. – Tomasz Szymulewski Apr 12 '22 at 09:18
0

Adopting from SlingHttpServletRequest is not always possible. And taking into consideration the fact that you adapt always from one class even if you have more that one class in adaptables field (in case you adapt from request, you have the resource to via the getResource and in case you adopt from resource the slingRequest object field will be null).

That was my case, I had to adopt from Resource and I had to inject some stuff to my Sling Model. To do this I used ThreadLocal, looks like there is no other way of doing this.

Here are some articles about how to do this:

  1. https://github.com/Adobe-Consulting-Services/acs-aem-samples/blob/master/core/src/main/java/com/adobe/acs/samples/filters/impl/SampleThreadLocalFilter.java
  2. https://www.javacodegeeks.com/2012/05/threading-stories-threadlocal-in-web.html
  3. https://github.com/luontola/dimdwarf/blob/453f7aee9efc364ebad80531c05081e255323c07/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/context/ThreadContext.java

I created an util class like this:

public final class SomeThreadContext {

    private static final ThreadLocal<Boolean> SOME_BOOLEAN_PROPERTY = new ThreadLocal<>();

    private SomeThreadContext() {
    }

    public static void setSomeFlag(boolean someFlag) {
        if (SOME_BOOLEAN_PROPERTY.get() != null) {
            throw new IllegalStateException("Flag already set up.");
        }
        SOME_BOOLEAN_PROPERTY.set(someFlag);
    }

    public static boolean isSomeFlagEnabled() {
        return SOME_BOOLEAN_PROPERTY.get() != null && SOME_BOOLEAN_PROPERTY.get();
    }

    public static void tearDown() {
        if (SOME_BOOLEAN_PROPERTY.get() == null) {
            throw new IllegalStateException("Flag already torn down.");
        }
        SOME_BOOLEAN_PROPERTY.remove();
    }
}

You should use setSomeFlag before creating a model (it can be filter or other place), isSomeFlagEnabled should be used inside model and you always have to use tearDown after you will end using the model (you can do this in the final block).

You can have as many params as you need, the most important thing is to always clean your ThreadLocal after you finish working on it. If you don't do this correctly this may lead to memory leak.

Tomasz Szymulewski
  • 2,003
  • 23
  • 23