Accessing HttpServletRequest object in a normal Java class from Spring - java

I have a normal Java class in a Spring MVC 3.06 web application.
In this class I would like to inject or get hold of the HttpServletRequest object in a method.
I know I can pass this around, but I was wondering how can I get hold of the request without passing it in to the method. Perhaps using annotations or similar?
Also, what are the "real" concerns with getting hold of the request this way, except some peoples opinions of it being ugly coding. I mean, is it unstable to access it this way?
Preferably non application server dependent way.
I have seen
(HttpServletRequest) RequestContextHolder.getRequestContext().getExternalContext().getNativeRequest()
but this doesn't seem to work for Spring MVC 3.06 . RequestContextHolder doesn't have the method getRequestContext().

Use
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
I'm not sure where you got RequestContextHolder.getRequestContext(), that's completely wrong.
is it unstable to access it this way?
No, it's stable enough, assuming you're always running the code as part of an HttpServlet request thread. The main issue is that yes, it's ugly, and it makes your code hard to test. That is reason enough not to use it.
If you must use it, then decouple it from your code, e.g.
public void doSomething() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
doSomething(request);
}
void doSomething(HttpServletRequest request) {
// put your business logic here, and test this method
}

#Context HttpServletRequest httpServletRequest =null;
use this

Related

Java: How do I unit test where there are encapsulated injected or generated dependencies?

SUMMARY:
I have a self-contained class for performing a proxied login and then filling a HttpServletResponse object with authentication content a browser can use. When testing my code, how can I provide mocked services into a class that has no setters?
DETAILS:
I've severely edited my proxied login code into this snippet.
It asks the server for a login form.
It sends back the credentials.
It gets the server's approval and passes it to the browser
(response).
The trimmed code looks like this:
private static final Log log = LogFactory.getLog(MyClass.class);
#Inject()
private UserService userService;
public void performProxyLogin(HttpServletResponse response,
UserDTO userDTO, String url) {
String username = getUsername(userDTO);
String password = getPasswordFromUserService(username);
// MyRequest only has data, organizing a Http Request.
MyRequest myRequest = prepareInitialGetRequest(url);
// processURLRequest() encapsulates use of HttpURLConnection.
// MyResponse only has data, organizing a Http Response.
MyResponse myResponse = processURLRequest(myRequest);
myRequest = prepareLoginRequest(myResponse, username, password);
myResponse = processURLRequest(myRequest);
// Transfer data into the response, and from there into the browser.
fillResponseWithProxiedResult(response, myResponse)
}
To make this work I think I need to inject a mocked Log or LogFactory, a mocked UserService, and a way of getting a mocked HttpURLConnection.
However, all of the advice I've seen involves code with setters, which the test suite can use to plug in mocked objects.
How do I provide my class its needed mocked objects?
Bite the bullet and provide a package-private setter for this field.
If you want to use mocks, there's no value in letting the injection framework set up a mock which you can inject, since you're adding more ceremony and overhead to the set-up of your test.
If you want to validate that you have a service injecting correctly, you wouldn't want to use mocks at all (think "integration test" with real or pseudo-real components).
Many of the other answers hint at it, but I'm going to more explicitly say that yes, naive implementations of dependency injection can break encapsulation.
The key to avoiding this is that calling code should not directly instantiate the dependencies (if it doesn't care about them). This can be done in a number of ways.
The simplest is simply have a default constructor that does the injecting with default values. As long as calling code is only using the default constructor you can change the dependencies behind the scenes without affecting calling code.
This can start to get out of hand if your dependencies themselves have dependencies and so forth. At that point the Factory pattern could come into place (or you can use it from the get-go so that calling code is already using the factory). If you introduce the factory and don't want to break existing users of your code, you could always just call into the factory from your default constructor.
Beyond that there's using Inversion of Control. I haven't used IoC enough to speak too much about it, but there's plenty of questions here on it as well as articles online that explain it much better than I could.
If it should be truly encapsulated to where calling code cannot know about the dependencies then there's the option of either making the injecting (either the constructor with the dependency parameters or the setters) internal if the language supports it, or making them private and have your unit tests use something like Reflection if your language supports it. If you language supports neither then I suppose a possibility might be to have the class that calling code is instantiating a dummy class that just encapsulates the class the does the real work (I believe this is the Facade pattern, but I never remember the names correctly)]

How to test code that needs passed HTTPServletRequest

I'm running some Scala code (with Java socialAuth library) that requires an HTTPServletRequest to be passed in as a param.
def myClass(prov: String, site: String, request: HttpServletRequest): {
//some initial code here
val session = request.getSession()
session.setAttribute(/*some params*/)
//code continues...
}
So the HttpServletRequest seems like a really cool way of storing session variables and passing a session between methods. However, I'm not quite sure how to test this code, as I don't really understand what the HttpServletRequest interface is.
I've done a bit of research, but I was wondering if anyone could clarify for me. HttpServletRequest is an interface, which means it can't be instantiated on its own. How, then is it used in code?
EDIT: as in, when a method takes an HttpServletRequest as a parameter, what implementing class is usually passed in?
FOLLOWUP: Based on the answers given, HttpServletRequest is implemented differently by different servers; Ireeder pointed out, for example, that Apache even has multiple implementations. How, then, does code specify that the server needs to use its implementation? In other words, lets say I have test code that uses myClass:
def otherClass(){
val site = "www.example.com"
val provider = "twitter"
val mockRequest = mock(HttpServletRequest.class) //using https://code.google.com/p/mockito/. (eclipse throws error..not too sure about syntax but throwing up this example quickly, so will edit later)
myClass(provider, site, mockRequest)
}
I assume this is OK for testing, as Mockito creates a mock object, but when otherClass() needs to be implemented on a server, how is its code adjusted? (Sorry, I'm a bit new at this, so bear with me...) If val mockRequest needs to be implemented with whatever HttpServletRequest implementation is used by the server (Apache, Oracle, etc), how does the user specify this in otherClass? Will something like this change:
//deleted line: --val mockRequest = mock(HttpServletRequest.class)
//changed line: myClass(provider, site, mockRequest) to below:
myClass(provider, site, javax.servlet.http.HttpServletRequest)
be interpreted and implemented correctly by the server?
Container implementers like Oracle or Apache extend the HttpServletRequest interface with their own implementations that actually do something. You could do the same for your testing, or use something like Mockito to mock it.
The only time you should be providing an implementation of an HttpServletRequest is at unit testing time, not when your code is running in a servlet container. The container will pass you its own HttpServletRequest, and your code should not care about the exact implementation of that interface. It should only use the methods provided by the HttpServletRequest interface so that it is independent of the container it is running in.
If you need to test the behavior of your code when it's running in servlet container, you can do manual testing, or use a testing framework that makes HTTP requests, like HttpUnit
Spring users can use the class MockHttpServletRequest (JavaDoc)

How to define RequestMapping prioritization

I have a situation where I need the following RequestMapping:
#RequestMapping(value={"/{section}"})
...method implementation here...
#RequestMapping(value={"/support"})
...method implementation here...
There is an obvious conflict. My hope was that Spring would resolve this automatically and map /support to the second method, and everything else to the first, but it instead maps /support to the first method.
How can I tell Spring to allow an explicit RequestMapping to override a RequestMapping with a PathVariable in the same place?
Edit 2: It seems that it would work if the /support mapping came before the /{section} mapping. Unfortunately we have dozens of controllers containing numerous methods with RequestMapping. How can I make sure that the controller with the /{section} mapping is initialized last? Or would a pre-interceptor be the way to go?
Edit 1: This is simplified, I know that having those two RequestMapping alone wouldn't make much sense)
Using Spring you can extend the org.springframework.web.HttpRequestHandler to support your scenario.
Implement the method:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
Use it to analyze the incoming request, determine if the request url is part of your special subset of request url's and forward to the appropriate location.
Ex:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/** You will want to check your array of values and have this data cached **/
if (urlPath.contains("/sectionName")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("sections" + "/" + urlPath);
requestDispatcher.forward(request, response);
}
}
And setup your sections such as:
#RequestMapping(value={"/sections/{sectionName}"})
This will not interfere with any of your pre-existing controller mappings.
If 2 these methods are defined in 2 different controllers your problem is that you have 2 controllers mapped to same URL. You do not control the order of controllers initialization right now, so the order is random.
I think you need /support mapping to be initialized before /{section}.
To achieve this try to define that controller "section" depends on controller "support". If this will not help try to put both methods together to one controller and put method mapped to "support" before "section"
I this does not work here is other suggestion. What "section" is? If it can accept limited number of values it should be defined as enum. I believe that in this case everything will work as required if support and section methods are in one controller or in separate controllers.
Good luck.
This not seems to be a problem, this is a valid mapping. If you have a look to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
In the section 16.3.2 Mapping Requests With #RequestMapping exists two methods doing exactly the same that you are trying.
To be sure that your classes are being compiled try to add a #RequestMapping("/someprefix") at class level to see if the URL is being exposed as you want.
I verify your example locally using the version 3.1.0.RELEASE and no issue were present.
As a workaround (and also to provide a well-understand REST URI add some context to your second mapping:
#RequestMapping(value={"client/support"}) // i.e: if you are working with clients
public ModelAndView getsupport(#PathVariable Long supportId){
// do your code here something here
}
Of course that this is valid if this is the unique controller present in the system, otherwise you must use RequestMapping at class level as I suggested above.
I hope this helps.
I am not seeing this behavior with Spring 3.1.2, it could potentially have been a bug with an older Spring version. Here is a gist which runs through without any issues for me - https://gist.github.com/3802254

How to access session from struts form object

Might be a bit of a noob question, but can I access a variable stored on the session from within a struts Form object?
public class MyForm extends ActionForm {...}
We have developed and maintained a very large project using Struts 1. I know your problem, we have an ActionContext class, with an ActionContextFilter, the filter binds the request and response objects to current thread using a ThreadLocal member (and obviously it unbinds them at the end of the process).
Now we can access request, response and ... using ActionContext.getCurrentContext().getRequest() and ActionContext.getCurrentContext().getResponse().
I believe the same thing can help you alot.
By the whole idea was from Clinton Begin's (the author of iBatis) sample PetStore; He have built a good extension around Struts 1 in that sample. I recommend you to review the whole work.
You need to set value to the form either in actionServlet (or) JSP. I don't think you can directly access request here (unless you do some customization).
You can retrieve an attribute in the session by using the HttpServletRequest:
request.getSession(false).getAttribute("yourAttributeName");
Have'nt tried at home but you may use:
private HttpServletRequest request;
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.request = request;
}
and store the request in a local field for later use as described above.

#Autowired HttpServletResponse

I'm looking for a way to autowire HttpServletResponse. It doesn't work with spring out of the box, but I've found this description. This works but is sort of annoying, in that spring obviously has a mechanism to make objects request scoped (i.e. HttpServletRequest) and this seems to be a hack bolted on top.
Is there a way to hook into the same mechanism that spring uses for HttpServletRequest? And, any idea why spring team decided to only make HttpServletRequest autowire capable (and excluded HttpServletResponse)?
Perhaps there is some workaround, but it's not that obvious, because it's not the way it's meant to be. Spring MVC is meant to have singleton #Controller beans that provide #RequestMapping methods which take the request and response as arguments.
If you need the response in another place (the service layer) - don't do it. The response should not go beyond the web (controller) layer.
To inject the response, you need:
- to store the response in a ThreadLocal
- to make a factory bean that returns the current response
About the example code you showed - I'm not sure if you are not going to need the factory bean to return a proxy (implementing HttpServletResponse), which in turn to return the current response. And it gets rather complicated.
But ultimately - you should not do that. If you need to intercept multiple controller invocations, use an mvc-interceptor. If you really need to use an aspect, you can get the response if it is passed as argument to the intercepted method.
Can you simply include the request in the method handle?
#RequestMapping(method=Method.GET, value="myUrl")
public String doGet(HttpServletResponse response){//spring will put the response in for you
...
}

Categories

Resources