I wrote an HttpServletRequestWrapper named HTTPRequest that reads the full HTTP POST body for further use. This one is based in the code at http://natch3z.blogspot.com/2009/01/read-request-body-in-filter.html
My Jersey server application needs to get this wrapper to read the body. Unfortunately, I don't know how to do that.
I've tried putting
#Context HTTPRequest request;
but it does not work (Missing dependency for field).
I've tried too doing:
#Context HttpServletRequest request;
then casting to HTTPRequest, it didn't work neither ($ProxyXXX cannot be cast to HTTPRequest).
I've searched for information in the Internet but I cannot find anything regarding this. Any idea? :)
Thanks!
I don't quite understand: HTTPRequest is your objects extending the HttpServletRequestWrapper, right?
So if you want Jersey to inject it via the #Context annotation, you need to implement the ContextResolver. Actually in your case it should be easy:
#Provider
HTTPRequestContextResolver implements ContextResolver<HTTPRequest> {
#Context HttpServletRequest request;
HTTPRequest getContext(Class<?> type) {
return new HTTPRequest(request);
}
}
Updated: If you already wrapped the original request in a filter, you may have a problem to get it, since Jersey wraps the original request using the dynamic proxy.
Related
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;
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 have a RESTful server implementation as well as a library for clients to make the calls, all using JAX-RS. The server components are divided up into interface FooResource and implementation FooResourceService.
In order for the client and server libraries to share RESTful path and other definitions, I wanted to split out the FooResource interface into its own project:
#Path(value = "foo")
public interface FooResource {
#GET
public Bar getBar(#PathParam(value = "{id}") int id) {
I want to set some headers in the response. One easy way to do this is to use #Context HttpServletResponse in the method signature:
public Bar getBar(#PathParam(value = "{id}") int id, #Context HttpServletResponse servletResponse) {
But the problem is that this exposes implementation details in the interface. More specifically, it suddenly requires my REST definition project (which is shared between the client and server library) to pull in the javax.servlet-api dependency---something the client has no need up (or desire for).
How can my RESTful resource service implementation set HTTP response headers without pulling in that dependency in the resource interface?
I saw one post recommending I inject the HttpServletResponse as a class member. But how would this work if my resource service implementation is a singleton? Does it use some sort of proxy with thread locals or something that figures out the correct servlet response even though the singleton class is used simultaneously by multiple threads? Are there any other solutions?
The correct answer seems to be to inject an HttpServletResponse in the member variable of the implementation, as I noted that another post had indicated.
#Context //injected response proxy supporting multiple threads
private HttpServletResponse servletResponse;
Even though peeskillet indicated that the semi-official list for Jersey doesn't list HttpServletResponse as one of the proxy-able types, when I traced through the code at least RESTEasy seems to be creating a proxy (org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy#xxxxxxxx). So as far as I can tell, thread-safe injection of a singleton member variable seems to be occurring.
See also https://stackoverflow.com/a/10076327/421049 .
So injecting HttpServletResponse seems like a no go. Only certain proxy-able types are inject-able into singletons. I believe the complete list is as follows:
HttpHeaders, Request, UriInfo, SecurityContext
This is somewhat pointed out in the JAX-RS spec, but is explained more clearly in the Jersey reference guide
The exception exists for specific request objects which can injected even into constructor or class fields. For these objects the runtime will inject proxies which are able to simultaneously server more request. These request objects are HttpHeaders, Request, UriInfo, SecurityContext. These proxies can be injected using the #Context annotation.
SecurityContext may be Jersey specific, as it's not stated in the spec, but I'm not sure.
Now those types mentioned above don't really do much for you because they are all request contexts and nothing to set the response.
One Idea though is to use a javax.ws.rs.container.ContainerResponseFilter, along with the HttpHeaders to set a temporary request header. You can access that header through the ContainerRequestContext passed to the filter method. Then just set the response header through the ContainerResponseContext, also passed to the filter method. If the the header is not specific to the context of that resource method, then it's even easier. Just set the header in the filter.
But let's say the header is dependent on the execution of the resource method. Then you could do something like
#Singleton
#Path("/singleton")
public class SingletonResource {
#Context
javax.ws.rs.core.HttpHeaders headers;
#GET
public String getHello() {
String result = resultFromSomeCondition(new Object());
headers.getRequestHeaders().putSingle("X-HELLO", result);
return "Hello World";
}
private String resultFromSomeCondition(Object condition) {
return "World";
}
}
Then the ContainerResponseFilter might look something like this
#Provider
public class SingletonContainerResponseFilter
implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext crc,
ContainerResponseContext crc1) throws IOException {
String header = crc.getHeaderString("X-HELLO");
crc1.getHeaders().putSingle("X-HELLO", "World");
}
}
And just so only the singleton classes run through this filter, we can simply use a #NameBinding annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.NameBinding;
#NameBinding
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface SingletonHeader {}
...
#SingletonHeader
public class SingletonResource {
...
#SingletonHeader
public class SingletonContainerResponseFilter
implements ContainerResponseFilter {
This is the only way I can think to handle this situation.
Resources:
Filters and Interceptors
Name Binding
#Path("/foo")
public interface FooResource {
#GET
#Path("{id}")
public Response getBar(#PathParam("id") int id) {
Bar bar = new Bar();
//Do some logic on bar
return Response.ok().entity(bar).header("header-name", "header-value").build()
}
}
Returns a JSON representation of the instance of bar with a status code 200 and header header-name with value header-value. It should look something along the lines of:
{
"bar-field": "bar-field-value",
"bar-field-2": "bar-field-2"
}
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
I need to grab a certain custom HTTP header value from every request and put it in WebSession so that it will be available on any WebPage later on. (I believe the Wicket way to do this is to have a custom class extending WebSession that has appropriate accessors.)
My question is, what kind of Filter (or other mechanism) I need to be able to both intercept the header and access the WebSession for storing the value?
I tried to do this with a normal Java EE Filter, using
CustomSession session = (CustomSession) AuthenticatedWebSession.get();
But (perhaps not surprisingly), that yields:
java.lang.IllegalStateException:
you can only locate or create sessions in the context of a request cycle
Should I perhaps extend WicketFilter and do it there (can I access the session at that point?), or is something even more complicated required?
Of course, please point it out if I'm doing something completely wrong; I'm new to Wicket.
I'd guess you need to implement a custom WebRequestCycle:
public class CustomRequestCycle extends WebRequestCycle{
public CustomRequestCycle(WebApplication application,
WebRequest request,
Response response){
super(application, request, response);
String headerValue = request.getHttpServletRequest().getHeader("foo");
((MyCustomSession)Session.get()).setFoo(headerValue);
}
}
And in your WebApplication class you register the custom RequestCycle like this:
public class MyApp extends WebApplication{
#Override
public RequestCycle newRequestCycle(Request request, Response response){
return new CustomRequestCycle(this, (WebRequest) request, response);
}
}
Reference:
Request cycle and request cycle
processor