I'm new to JAX-RS and I'm trying to understand how the #Context annotation works. I have a REST service and am currently using certain filters to do extra processing for different request types. Inside one of those filters is the following line:
public class SentryFilter {
#Context
HttpServletResponse response;
...
This value is used later on in the filter() method of that filter. The problem is that the response object is null. I've stepped through a debugger and can't determine why it's null.
From what I've read in the JAX-RS documentation, the #Context annotation for HttpServletResponse can be filled by the resource methods. So, I modified my the API I'm calling to include HttpServletResponse
public interface APIStuff {
#Path("deviceName")
#GET
#Sentry
String getDeviceName(#PathParam("deviceId") #Size(min = 1, max = 1024) final String deviceId, #Context HttpServletResponse httpServletResponse);
...
This returns the same HttpServletResponse is null error.
So the question is, where is this value supposed to be "filled"? The person who wrote the filter class obviously did so with the belief that the response object would be filled, so I don't think it's a matter of passing in #Context HttpServletResponse to the filter() method.
The #Context annotation allows you to inject request/response context details into JAX-RS provider and resource classes. Injection can be performed into a class field, a bean property or a method parameter.
The types available for injection are listed in this answer.
You haven't provided any details about how your application is deployed, but be aware that HttpServletResponse is available for injection only when the application is deployed in servlet containers (Tomcat, for example). It might be your problem.
#Context varies with usage and depends on what is actually being injected. If you are injecting the HttpServletResponse, it needs to be part of the method signature. This is because most beans are implemented as a singleton, and having multiple requests will just override the response if implemented at an instance level.
As an aside, IMO the API should support injecting the method-only '#Context' resources into a (for example) ThreadLocal<HttpServletResponse>
Your Filter that you posted does not extend javax.servlet.Filter, are you including the full signature? how is this filter being used?
As to why your resource method level injections are turning up null, are you sure it's actually being called within the servlet context?
As #cassiomolin said, you haven't provided any details about how your application is deployed, HttpServletResponse is available for injection only when the application is deployed in servlet containers (Tomcat, for example). It might be your problem.
I had similar problem with GrizzlyHttpServer.
Cause of my issue was, Grizzly provides similar abstractions to those offered by the Servlet specification: HttpHandler (Servlet), Request (HttpServletRequest), Response (HttpServletResponse).
So I had to use: import org.glassfish.grizzly.http.server.Request;
instead of: import javax.servlet.http.HttpServletRequest;
Related
This question took off because I read Arjan Tijms blogpost about JSF 2.3. There, he list all JSF artifacts which can be injected via CDI. Although HttpServletRequest is mentioned, HttpServletResponse doesn't appear on the said list which I didn't believe at first.
To try things out, I setup a simple Server (JavaEE8, Wildfy22):
#Inject private HttpServletRequest req; works just fine
#Inject private HttpServletResponse res; throws DeploymentException: WELD-001408: Unsatisfied dependencies for type HttpServletResponse
I don't see why HttpServletResponse should not be injectable. After all, the goal was to replace convulent method chains by a concise injection.
In case of HttpServletRequest, FacesContext.getCurrentInstance().getExternalContext().getRequest(); can now be shortened to the above injection.
Well, in case of HttpServletResponse, there is no injection candidate to replace FacesContext.getCurrentInstance().getExternalContext().getResponse(); as shown above.
Summarized: Why is HttpServletRequest injectable via CDI but HttpServletResponse isn't?
There's not a single good answer here.
To start with, HttpServletRequest is produced by CDI, not Faces. As for HttpServletResponse I'm not sure why it wasn't original included in CDI, but I do know that all the Servlet artefacts should originally not have been provided by CDI.
Instead, CDI should have asked Servlet to provide "producers" for them (technically, build-in beans). Jakarta Transactions (JTA back then) did something similar)
Currently, CDI doesn't want to enhance or expand the Servlet artefacts, and with good reason. CDI is focussing on its core bean model and injection.
However, in Servlet there is a huge misunderstanding of what it means to provide producers. At least one person in Servlet thinks it's about providing integration points, or about Servlet having to become completely CDI based, or about Jetty having to support all 10 CDI implementations out there (there are only 2, but that aside).
This discussion has been going on for at least 8 years. Issues have been opened and closed again.
I'm a Servlet member myself so I hope I have some influence, but still have not been able to get this resolved.
We could alternatively have Faces provide HttpServletResponse, but Faces also does not own that type, and it would likely only contribute to the confusion.
As said already injecting the HttpServletResponse is not supported by CDI by default. The Servlet module from Apache DeltaSpike however allows for injectable servlet objects such as the HttpServletResponse. So there is no need for writing a custom CDI Producer or #Produces method in order to inject the HttpServletResponse via CDI.
When injecting HttpServletRequest in Jersey/JAX-RS resources, the injected value is a proxy. E.g.:
#Path("/myResource")
class MyResource {
#Inject
HttpServletRequest request;
...
}
Will inject a Proxy object for the requested HttpServletRequest. I need access to the actual HttpServletRequest instance object, because I want to use some container specific features that are not in the proxied HttpServletRequest interface.
Is there a way in jersey to have access to the actual object via injection? I know that in older versions of Jersey you could inject a ThreadLocal<HttpServletRequest> to achieve this. But that doesn't seem to be supported in jersey 2.15 anymore.
Rationale: My code depends on functionality in org.eclipse.jetty.server.Request which implements HttpRequest, and adds functionality for HTTP/2 push. I would like to use that with Jersey/JAX-RS.
Don't make your resource class a singleton. If you do this, there is no choice but to proxy, as the request is in a different scope.
#Singleton
#Path("servlet")
public class ServletResource {
#Context
HttpServletRequest request;
#GET
public String getType() {
return request.getClass().getName();
}
}
With #Singleton
C:\>curl http://localhost:8080/api/servlet
com.sun.proxy.$Proxy41
Without #Singleton
C:\>curl http://localhost:8080/api/servlet
org.eclipse.jetty.server.Request
There are other ways your class can become a singleton, like registering it as an instance
You can aslo inject it as a method parameter. Singleton or not, you will get the actual instance
#GET
public String getType(#Context HttpServletRequest request) {
return request.getClass().getName();
}
See Also
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey
As Op said that
I know that in older versions of Jersey you could inject a ThreadLocal to achieve this.
I just want to add some code here which could implement this for those who are still using an older version of jersey like I do:
#Context ThreadLocal<HttpServletRequest> treq;
And a link for this:Thread access to #Context objects?
Hope that would help.
I came across authentication code in my company's java code. The application is a set of several REST services built on Spring MVC. There is a method that gets called in one of the authentication services on the HttpServletRequest object called getHeader(). And the method retrieves an AuthId. Why would they use HttpServletRequest in a spring MVC application? What are the benefits of using this servlet type code in the spring app? What would this method do? Any alternatives?
Spring MVC provides a lot of fabulous abstractions on top of HttpServletRequest, so you can avoid its low-level implementation details. You rarely need to access it directly.
For example, you could get a header value like Content-Type like this:
#GET
#Path("/myService")
public Response doSomething(#HeaderParam("Content-Type") String contentType) {
...
}
But there are times when you do need to access the HttpServletRequest directly--usually when you are using another API that demands it. If you are using some other library with a method you need that takes HttpServletRequest, then you got to grab it from Spring MVC directly.
For example, check out this method in this random UrlUtil class:
public static String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
//Get a path segment
}
You have no choice but to grab HttpServletRequest from Spring MVC.
Spring MVC is built on the Servlet API. Anything you could do with a Servlet, you can therefore do with Spring MVC. What the Spring MVC framework provides is a wrapper to code a web application in a specific architectural style. This wrapper adds behavior and some times simplifies tasks.
Why would they use HttpServletRequest in a spring MVC application?
In this case, because it is the most direct way to get the header.
What are the benefits of using this servlet type code in the spring
app?
Spring doesn't have to wrap anything. You get it directly from the source.
What would this method do?
Read the javadoc.
Any alternatives?
In a #Controller class' handler method, you can declare a parameter annotated with #RequestHeader and have Spring pass an argument that it retrieves from the HttpServletRequest headers.
This is, by default, restricted to #Controller methods annotated with #RequestMapping. If your service class is a HandlerInterceptor, Filter, or other type of class and simply has a reference to the HttpServletRequest object, there is nothing more you can do than retrieve it directly with getHeader(String).
Here is an alternative : Spring MVC define the parameter annotation #RequestHeader to read httpServletRequest headers :
#RequestMapping(...)
public #ResponseBody String myMethod(#RequestHeader String AuthId){
//the value of the parameter AuthId is the value of request header named AuthId
...
}
I have a REST- Server here using JERSEY. I must log the IP (better the DNS) of the calling client.
Can somebody point a direction which injection annotations to use ?
Searched "#Context", but could not find anything fitting.
Thanks
Gerd
you could add #Context HttpServletRequest request as a parameter to your request handler method. And then get a hold of the client IP with request.getRemoteAddr()
In case you use Grizzly-Jersey combo, thats the way to do it:
#Context
private java.lang.ThreadLocal<org.glassfish.grizzly.http.server.Request> grizzlyRequest;
Option 2 for Grizzly-Jersey combo.
Place in the declaration of the class (extender of ContainerRequestFilter in my case)
#Inject
private javax.inject.Provider<org.glassfish.grizzly.http.server.Request> request;
and later in the code use this.
request.get().getRemoteAddr()
I dug around and I've found the resolution in the jersey's jira.
Note that they recommend to be used #Inject instead of #Context
I've tried to use
#Context
private HttpServletRequest servletRequest;
which is recommended widely but servletRequest was always null.
*comment servletRequest was null because I was used GrizzlyHttpServerFactory for creating HttpServer. If you want to have servletRequest then you need to deploy it with WebappContext. Take a look here for details
In the Java Servlet API, the only way to get the ServletContext is through an instance of HttpSession (Javadoc).
What if I don't want to create a session and only need the servlet context? In other words, why is there no getServletContext() method in the HttpServletRequest class?
EDIT
I know I can get the ServletContext from the servlet itself, since it receives it during its initialization. However, I cannot get it from a HttpServletRequest alone, even though it's linked to a servlet. So what if I have a request, but no reference to any servlet?
getServletContext() is part of GenericServlet which is the parent class for HttpServlet so you should be able to call it in your servlet implementation.
Edit:
HttpServletRequest inherits getServletContext() from ServletRequest since servlet 3.0, so it looks like you will have to pass a context along with the request and response objects if you have to use a version prior to 3.0.
It's just that every entity working with requests (servers, filters, pages) has its own getServletContext (or init())
Your servlet class has a getServletContext() method you don't need to go to the request.
This makes sense, the servlet itself has a context provided by the container, this is independent of any particular request.