I'm building an API using Jersey on the Glassfish 3.1 server and need to get access to the HttpServletRequest object in order to get certain headers, caller's ip, etc. I could just inject it into every API method call but it seems more efficient to just do it globally. Is it safe to inject it at the class level like in the snippet below or will this cause some kind of concurrency issues with Glassfish?
#Path("/myapi")
#RequestScoped
public class MyApiResource {
#Context private UriInfo context;
#Context private HttpServletRequest request;
It is safe. Don't use the #RequestScoped annotation - JAX-RS resources are request scoped by default. That means a new instance gets created for each request hence no concurrency issues.
Related
I am trying to build a token based authentication and authorization system using Apache CXF and Spring. I am completely following this fantastic post for doing this.
But I am stuck in a problem with my AuthorizationFilter at the very beginnig. I have seen many posts, apache JIRA, github comments about it, but could not yet found the workaround about this seemingly CXF issue.
#PreMatching
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
private ResourceInfo resourceInfo;
#Context
public void setResourceInfo(ResourceInfo resourceInfo) {
this.resourceInfo = resourceInfo;
}
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
Method method = resourceInfo.getResourceMethod();
In the above code, the injected resourceInfo is a proxy object, and it has none of the associated properties present. So, anything from that resourceInfo object is returning null, more specifically resourceInfo.getResourceMethod() is null, leading to NPE.
This is the JIRA post pertaining to this very issue, saying that:
In some circumstances (like using #ApplicationScoped annotation for example) the CDI runtime will create a proxy class for a particular bean. As the result, the CXF side is going to bind the particular provider metadata to this proxy instance. It looks logical and unambiguous.
However, the interesting things are happening when CXF will try to inject contextual proxies (#Context annotations) into the provider instance. The injections are successful but the target object for them will be the proxy instance (not the real instance behind it). Consequently, at runtime, when the proxy delegates the call to a backing instance, all contextual proxies are null in there (simply put, not set).
Referring to the recent discussions with Sergey Beryozkin, the best solution would be to delegate the #Context annotation to CDI framework (as such, relieving the CXF from doing the injection work). This proposal may need a support from the JAX-RS specification side.
Simpler (interim?) possible solution would be to complement the CDI injection with #Context injection (delegating this work to the CXF as it works right now for non-proxy beans and non-CDI deployments). This could be done by observing ProcessInjectionTarget events and supplying our own InjectionTarget (have working PoC for this approach).
Regarding constructor injection, it seems like CXF does not support passing the arguments to provider constructor (in case of CDI, w/o #Context annotation) so I it would be another (separate) issue to look at.
Can someone help me point out what is this simpler approach is all about:
Simpler (interim?) possible solution would be to complement the CDI injection with #Context injection (delegating this work to the CXF as it works right now for non-proxy beans and non-CDI deployments). This could be done by observing ProcessInjectionTarget events and supplying our own InjectionTarget (have working PoC for this approach)
Or is there any other way, where Spring Framework can inject the ResourceInfo object in a correct way?
I have registered the filters like this in my applicationContext.xml :
<jaxrs:server id="endpoints">
<jaxrs:providers>
<ref bean="authenticationFilter" />
<ref bean="authorizationFilter" />
</jaxrs:providers>
</jaxrs:server>
The problem is the #PreMatching annotation.
Global binding annotation that can be applied to a container request filter to indicate that such filter should be applied globally on all resources in the application before the actual resource matching occurs.
The key is highlighted part "before the actual resource matching occurs". So even before the resource is matched to the request, the filter is called. And if there is no resource matched yet, then it is impossible to get any information from the ResourceInfo. If you just remove the #PreMatching annotation, then the filter will be called after a matching resource is found, and you will be able to access all the info from the ResourceInfo.
I would like to know how autowiring of HttpSession works.
If we declare like below:
#Autowired
private HttpSession httpSession;
When exactly in the Spring workflow, httpSession variable declared above will be initialized with request.getSession(true)?
I don't understand why you want to autowire HttpSession but here is how autowiring works.
To Autowire a class you need to specify it as a bean either by using annotations (#Controller, #Service, #Repository, #Component) or by declaring #Bean in config class. Once you define a bean Spring autowires or constructs the objects when the spring context initializes (during server startup for webapp and you explicitly initialize spring context in case console/standalone app).
Since HttpSession can only be fetched from HttpServletRequest object, you cannot initialize it during application startup because there is no HttpServletRequest during startup. If you want some logic to implement before fetching the HttpSession you can create a util method like this
public getHttpSession(HttpServletRequest request) {
// put your logic here and return session object
}
I am writing an application that uses RMI to invoke EJBs. The EJBs are Stateless; the business requirements do not require conversational state with the client.
One of the parameters to the EJB method calls is a "User" object used to determine if the user associated with the call has permission to perform the action. We are not using container-managed auth-auth: the User object is just a POJO provided by the remote client.
I would like to make this User object globally available/injectable within the "session" or invocation context. I am aware that Stateless EJBs do not have a "session" in the EJB sense; what I mean by "session" is "the current invocation". For example, say we have only one remote EJB with two methods:
myStatelessEjb.add(Thing, User)
myStatelessEjb.update(Thing, User)
These methods call many more methods: there are other EJBs involved, Bean Validators, etc. Rather than passing-around the User object everywhere, I would like to make the User object globally available/injectable with the context of the current remote EJB invocation.
I could of course just pass around the User object or encapsulate it with "Thing", but I thought maybe it would be a better design to not "pollute" my objects and APIs with User since it's a cross-cutting concern.
Notes (for emphasis):
I am using RMI.
There is no HTTP session, because I am using RMI.
I am not using container-managed auth-auth.
I am using container-managed transactions.
Is there a standard technique suitable for this problem? e.g. Perhaps the remote client should invoke a Stateful EJB which will hold the User, or maybe ThreadLocal is appropriate, or maybe I can hook onto the container-managed transaction, or maybe there's already an applicable session/context I'm unaware of.
Easiest way would be to store the user in a #RequestScoped CDI bean and inject that as required:
#RequestScoped
public class RequestUser {
private User user;
//getter and setter for user
}
#Remote
#Statless
public class MyRemoteInterface {
#Inject
private RequestUser requestUser;
...
public void foo(User user, Bar bar) {
request.setUser(user);
...
}
}
#Stateless
public class OtherEJB() {
#Inject
private RequestUser user;
public void doBar(Bar bar) {
User user = user.getUser();
...
}
}
While #SessionScoped is useful for HTTP sessions only, #RequestScoped has broader applicability:
public #interface RequestScoped
Specifies that a bean is request scoped.
The request scope is active:
during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the
container calls any ServletRequestListener or AsyncListener,
during any Java EE web service invocation,
during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB
timeout method and during message delivery to any EJB message-driven
bean, and
during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment.
Finally I have managed to setup the context for some integration test and to test methods that expect #PathVariable or #ModelAttribute. Still, I cannot figure out how can I setup the HTTPServletRequest used inside the controller.
MyController {
#Autowired
private HttpServletRequest request;
}
The request never updates while I'm running the test.
I might misunderstand something (as far as I'm new to Spring).
How can I achieve this?
Thanks in advance for the answer!
Isn't the HttpServletRequest passed in to the controller via a method parameter?
Use #Autowired to connect an instance variable to a Spring context bean.
Maybe you can have a look at MockHttpServletRequest for testing Web controllers.
I didn't have time to fill in the answer: I am using MockHttpServletRequest and Spring 3.1.2.
I have managed to solve it not by using #Autowired, but by getting the request bean from the controler. Something like this:
mockRequest = (MockHttpServletRequest) applicationContext.getBean ("request");
Hope that this will help someone else ...
In Rest API design, I am wondering what the exact purpose of the context annotation is?
private HttpServletRequest request;
#Context
public void setRequest(final HttpServletRequest req) {
request = req;
}
The purpose is to indicate that the request property should be set from the context.
#Context is used to inject various HTTP-ish contextual data, from here:
In general #Context can be used to obtain contextual Java types related to the request or response.
API docs (Not horribly useful IMO. Or, perhaps more accurately, horribly-useful.)
This annotation is used to inject information into a class field, bean property or method parameter.
JAX-RS #Context to get the ServletContext, and WebApplicationContextUtils to get the Spring application context, with this Spring application context, you are able to access and get beans from Spring container