Why is HTTPServletRequest injectable via CDI but HTTPServletResponse isn't? - java

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.

Related

HttpServletResponse with #Context annotation always null

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;

Spring MVC Controller as Liferay Portlet and Servlet

We are trying to have a spring MVC Controller that works as a portlet and a servlet, in order to be deployed in a Liferay context or as a standalone version. But it seems that the we have a conflict if we decide to have multiple RequestMappings on the method level (as opposed to having just 1 mapping on the level of the controller). we get the error shown below.
Note that if we decide to just have a requestMapping on the level of the controller that hosts a servlet mapping and a portlet mapping, it works.
#RequestMapping({"view", "/"})
The controller that does not work:
#Controller("controller")
#RequestMapping("VIEW")
public class MyController {
#RenderMapping
public ModelAndView doView(RenderRequest request, RenderResponse response) throws Exception {
HttpServletRequest portletHttpReq = PortalUtil.getHttpServletRequest(request);
HttpServletResponse portletHttpResp = PortalUtil.getHttpServletResponse(response);
return doView(portletHttpReq, portletHttpResp);
}
#RequestMapping(value="/home")
protected ModelAndView doView(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
// do something
return new ModelAndView("view");
}
}
The resulting error:
[...]
Caused by: java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/home] versus [view]
Do you have any suggestions on how we could implement such thing? What we would really like to avoid is having to maintain 2 controllers for every portlet/servlet.
Thank you.
I don't really think this is a good idea... the #RequestMapping annotation on the class level is going to cause problems for sure, simply because Spring portlet MVC expects the portlet mode, while Spring Web MVC expects a root URL.
Also, your code doesn't seem to be correct either, since ModelAndView exists in both the portlet MVC as the web MVC part of the Spring framework, and since you cannot import both, you'll have to specify the full package for one of them, and since you're not doing that either, your code is just wrong.
Except the technical issues, both portlets and servlet have different terminology and point of views. These are some key questions that pop up with me if I hear this:
What are you going to do about the different phases (ACTION and RENDER)
What about the the different portlet modes (VIEW, EDIT, HELP, ...)
What are you going to do about the specific portlet features (PortletSession, PortletPreferences, ...)
How are you going to handle the different kind of requests (ResourceRequest, ActionRequest, RenderRequest, PortletRequst, EventRequest vs HttpServletRequest)
How are you going to handle security? The portal container provides authentication for you, a standalone web application does not.
And these are just questions from a portlet mindset, I'm pretty sure there are also technical issues if you look at it from the web application point of view.
It makes much more sense to divide your code into a view layer and business logic. Put the business logic in a separate package or separate services, and build a separate portlet- and standalone application, using the same/shared business logic.

how can i use methods of that class such as getFormView(), processFormSubmission(... , ... , ... , ...) when rewriting my controllers?

can any one suggest any documentations on how to re-write SimpleFormController sub-classes to use annotated controllers instead, like how can i use methods of that class such as getFormView(), processFormSubmission(HttpServletRequest request, HttpServletResponse response, Object object,
BindException errors) when rewriting my controllers?
The need to rewrite these classes come as a result of the need to upgrade to the recent versions of Spring like 4.1.4
Like I have already stated, am upgrading my spring to 4.1.4-RELEASE and it looks like the SimpleFormController class was totally removed preceeding it's deprecation in 3

How do you configure a JAX-RS MessageBodyWriter on a per-request basis?

Essentially, I have a MessageBodyWriter that writes objects as JSON, and I'd like to be able to control some aspects of the output based on which resource method handled the request. However, the default lifecycle of #Provider classes is singleton (one per JVM), so I can't inject an instance of some configuration object. This leaves me with 2 obvious workarounds:
Use custom annotations: Each call to writeTo(...) includes the list of annotations on the method that was invoked, so I could check for the existence of some annotation. However, JAX-RS methods are already pretty laden with metaprogramming.
Use a ThreadLocal property map: Assuming one request per thread, but this approach breaks encapsulation a bit. The resource methods needs to be aware that there is some other class out there, looking for this map.
Is there a way to change the lifecycle of the Provider itself? I am using Jersey.
Not sure why you need a MessageBodyWriter Provider with per-request basis. If you just want to distinguish which methods are with JSON ouput and which are not, then jersey-json does already support.
And although the #Provider is singleton. You still can use per-request object within it like below.
#Provider
public class StViewProcessor implements ViewProcessor<ST> {
......
#Context
HttpServletRequest request;
public void writeTo(ST st, Viewable viewable, OutputStream out)
throws IOException {
System.out.println(request.getRequestURI());
...
}
}
And if you want to inject your instance per request, you can have a look at PerRequestTypeInjectableProvider. Here is a link about it.
The JAX-RS 1.1 spec requires that implementations support singleton providers and allows support for other lifecycles but doesn't suggest anything else along those lines. As far as I'm aware, pure Jersey doesn't support anything beyond singletons. With the jersey-spring contrib module, you get support for using Spring as Jersey's IoC container (where it gets its resource and provider instances from). I know Spring supports multiple lifecycles, including request, but I'm not sure if support for that is built into jersey-spring.

How do I get a HttpServletRequest in my spring beans?

I'm developing an app with a Flex-based front end and a Spring/Hibernate back-end.
To get Facebook integration working in the way I've got it currently, I need to read the cookies set in javascript on the front end on the back-end and do some validation during login to see whether the user is attempting to spoof his Facebook login.
This would be pretty easy, but I can't figure out how to get the HttpServletRequest. I'm using a pretty basic Spring config (this is my first real Spring app, and I'm pretty familiar with it now, but there's lots to it I've never looked at.)
I'm not using Spring MVC or Spring WebFlow or anything like that. I can get the ServletContext, but I haven't yet figured out how to get the request.
Any help?
If FlexContext is not available:
Solution 1: inside method (>= Spring 2.0 required)
HttpServletRequest request =
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
.getRequest();
Solution 2: inside bean (supported by >= 2.5, Spring 3.0 for singelton beans required!)
#Autowired
private HttpServletRequest request;
This is kind of Flex/BlazeDS specific, but here's the solution I've come up with. Sorry if answering my own question is a faux pas.
HttpServletRequest request = flex.messaging.FlexContext.getHttpRequest();
Cookie[] cookies = request.getCookies();
for (Cookie c:cookies)
{
log.debug(String.format("Cookie: %s, %s, domain: %s",c.getName(), c.getValue(),c.getDomain()));
}
It works, I get the cookies. My problem was looking to Spring - BlazeDS had it. Spring probably does too, but I still don't know how to get to it.
#eeezyy's answer didn't work for me, although I'm using Spring Boot (2.0.4) and it may differ, but a variation here in 2018 works thus:
#Autowired
private HttpServletRequest request;
this should do it
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getRequestURI();
The #Context annotation (see answers in this question :What does context annotation do in Spring?) will cause it to be injected for you.
I had to use
#Context
private HttpServletRequest request;
Better way is to autowire with a constructor:
private final HttpServletRequest httpServletRequest;
public ClassConstructor(HttpServletRequest httpServletRequest){
this.httpServletRequest = httpServletRequest;
}

Categories