request injection issue

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

request injection issue

Tom Palmer
Hi -
We have a model base class that provides access to the XSSAPI service so that we can do these transforms in model code rather than JSP (this is Slice 4.2 with AEM 5.6.1).  For XSSAPI.getValidHref(), the current request is required (you have to init with xssAPI = xssAPI.getRequestSpecificAPI(request)).

I've tried injecting the request into my model as follows:

    @Inject
    protected XSSAPI xssAPI;

    @Inject
    protected ServletRequest request;

From what I see in ContextRequestFilter, the request should be bound and therefore available for injection.  However, it's null.  I've tried the following:
- Binding SlingHttpServletRequest instead of ServletRequest
- Injecting the request object via the model constructor
- Injecting the ContextScope (to try to get the request manually)

with no luck.  In all other respects, Slice is working properly - no problems until this.  And the xssAPI field is injected fine.

Thoughts on how to do this?

Thanks -
- Tom
Reply | Threaded
Open this post in threaded view
|

Re: request injection issue

maciej.majchrzak
Administrator
Hi Tom,

Slice provides SlingHttpServletRequest through its SlingModule, so it's available for injection. Have you tried injecting SlingHttpServletRequest instead of ServletRequest? Something like this should work ootb:

public class MyModel {

  @Inject
  private SlingHttpServletRequest request;

  @Inject
  private XSSAPI xssAPI;

  //...
}

If it doesn't work, can you please provide me with more info about how your object looks like and how it's being created (or when it's used), e.g. through slice:lookup in jsp or modelprovider, injector?

Cheers
Maciej
Reply | Threaded
Open this post in threaded view
|

Re: request injection issue

Tom Palmer
Thanks Maciej -
OK, I now have the following working:

    @Inject
    private SlingHttpServletRequest request;

I had tried it before but was throwing an exception on null request, not realizing that their were valid cases where the model could have been created from modelProvider.get() and wouldn't have a request.  Now I just log it and I have a valid request when expected.

I'm all good but will relay another issue I had.  When trying to do unit tests on our models I ran into a related problem with the request.  We have a junit test setup for our models that sets up Guice/Slice pretty much as our BundleActivator does.  We use Mockito for all mocking needs.

I tried a variety of approaches but nothing worked - and having SlingModule final was a pain since I couldn't override nor do a Mockito.spy on it.  Ultimately, I was able to mock out ContextScope and get in front of the machinery to set my mock request.  Working ... but a bit of a challenge.

Thanks for the prompt help!
Reply | Threaded
Open this post in threaded view
|

Re: request injection issue

maciej.majchrzak
Administrator
The problem you have with unit tests is quite common I believe - and this is where DI and Slice may be of help. To make your model easily testable you may consider a couple of approaches:
1) Encapsulate XSSAPI object in some facade-like class, let's say MyXssAPI. This can be injected to your model, but doesn't require request initialization. This way you can easily mock it in you unit test and you won't need to bother hard-to-mock request class. Example code:
@SliceResource
class MyModel {

  @JcrProperty
  private String href; 

  private MyXssAPI xssApi;
  
  @Inject
  public MyModel(MyXssAPI xssApi) {
    this.xssApi = xssApi;
  }
  
  public String getHref() {
    return xssAPI.getHref(href);
  }
}

public class MyXssAPI {
  private XSSAPI xssAPI;
  @Inject
  public MyXssAPI(SlingHttpServletRequest request, XSSAPI xssAPI) {
    this.xssAPI = xssAPI.getRequestSpecificAPI(request);
  }
  public String getValidHref(String url) {
    return xssAPI.getValidHref(url);
  }
}

2) Extend Slice mapping by adding new post processor which will transform some annotated fields with use of XSSAPI. This would make your class very easily testable and you can reuse this for other models. Example code:
@SliceResource
class MyModel {

  @XssHref 
  @JcrProperty
  String href;
  
  public String getHref() {
    return href;
  }
}
For how to write an post processor please take a look at one of Slice's post processors, e.g. EscapeValuePostProcessor
Reply | Threaded
Open this post in threaded view
|

Re: request injection issue

Tom Palmer
I like #1 - obvious in retrospect ;)  Thanks again -