Loop in Spring Controller Method - spring

I have some very strange behaviour in one of my spring controller which I can not explain.
So this is what I have. Very simple controller.
#RequestMapping(value="/doSomething")
public void doSomething(#RequestParam int value, HttpSession session) {
System.out.println("Lorem");
// Some stuff later on done here
System.out.println("ipsum");
}
When I request the mapped URL the controller behaves as it whould have an infiniate loop inside. So it starts with the output "Lorem" then "ipsum" and instead of leaving the method it starts right from the beginning of the method again. It is not called multiple times from external. Does anybody know this behaviour or has any clue? Furthermore I could observe that the output speed slows down as memory drastically increases up to about 1.5 GB and 100% CPU usage spread all over every single core.Thanks for your help.

Your handler method doesn't seem right to me. Typically you need to return a string that will be resolved into a View by ViewResolver, eg:
#RequestMapping(value="/doSomething")
public String doSomething(#RequestParam int value, HttpSession session) {
// ....
return "somethingdone";
}

This is my understanding.
If a controller declares a void return type , Spring will attempt to infer the view name from the request URL.
In your case, it will assume the view name is "doSomething", and proceed on that assumption.
It does this using an implementation of RequestToViewNameTranslator, The default implementation of RequestToViewNameTranslator is DefaultRequestToViewNameTranslator
See this

Related

How to override a web api route?

I am trying to standardize an extension model for our REST API development team. We need to provide default implementation of routes, while allowing for custom implementations of routes that replace the default as well.
As a simple example if we have a GET route api/users like this:
public class DefaultUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = 0)]
public IEnumerable<string> DefaultGetUsers()
{
return new List<string>
{
"DefaultUser1",
"DefaultUser2"
};
}
}
We expect the default work like this:
Now a developer wants to change the behavior of that route, he should be able to simply define the same route with some mechanism to imply their implementation should be the one used, instead of the default. My initial thinking was to use the Order property on the Route attribute since that's what it appears to be there for, as a way to provide a priority (in ascending order) when an ambiguous route is discovered. However it's not working that way, consider this custom implementation that we want to override the default api/users route:
public class CustomUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = -1)]
public IEnumerable<string> CustomGetUsers()
{
return new List<string>
{
"CustomUser1",
"CustomUser2"
};
}
}
Notice the Order property is set to -1 to give it a lower priority value than the default, which is set to 0. I would have thought this would be used by the DefaultHttpControllerSelector, but it isn't. From the DefaultHttpControllerSelector:
And we end up with this exception being returned in the response:
Is it possible Microsoft just missed the logic/requirement to use Order as a route disambiguator and this is a bug? Or is there another simple way to override a route, hopefully with an attribute?
I have pretty much the same problem. I am creating a starter site, but I want users to be able to redefine to behaviour of a Controller, especially if there is a bug.
I use Autofac to resolve the Controller, but even when I register the new controller as the old one, the original one gets selected.
What I'll do is probably go with URL Rewriting. Especially since this issue is temporary in my case. However, I would be interested if someone has a better option.

Response.Clear() equivalent in MVC

I'm very new to MVC. How do I perform a Response.Clear() from within an MVC3 aspx page?
I have tried:
Response.Clear();
ViewContext.HttpContext.Response.Clear();
Neither of them seem to function at all, in that any HTML content before the statements remain in the output. The only thing that seems to work is Response.Close(), but of course that doesn't allow me to output anything afterwards.
The reason for wanting this simply a testing/debugging exercise - I just want to be able to clear the buffered output, from inline code in the aspx page, and output something else afterwards. Similar to what one could do with web forms.
Note, I don't want to perform this within the controller, as it means re-compiling every time I make a change, as well as losing session state. The point of this is to fiddle within the aspx page to avoid re-compiling each time.
Taken from your comment, that you want to mess with your code before an Action is executed and afterwards, the most ideal solution is to use custom ActionFilters:
public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}
OnActionExecuting is used to execute code before your Controller action is called, while OnActionExecuted is used after the action method has done its job.
So you hook up a custom filter like this:
public class MyCustomFilter : IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//put your custom response and shenanigans here
...
return;
}
}
After this you can decorate your controller method with this filter:
[MyCustomFilter]
public ActionResult ListSomething()
{
/* magic happens here */
}
There's a lot you can achieve here, but I suggest some further reading into this:
http://www.dotnet-tricks.com/Tutorial/mvc/b11a280114-Understanding-ASP.NET-MVC-Filters-and-Attributes.html
http://msdn.microsoft.com/en-us/magazine/gg232768.aspx
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs
http://msdn.microsoft.com/en-us/library/gg416513(vs.98).aspx
Sidenote: If this is just for learning and debugging purposes, I'd take a look at newer mvc versions (4, 5).
In stead of focussing on Response, perhaps you should focus on what you wish to return in your controller method.
If you wish to return a full rendered View
return View("myView");
If you wish to return a PartialView
return PartialView("myPartialView");
If you wish to return a FileStream
return File(myBytes, "filename.ext");
If you wish to return a Json string,
return Json(myObject);
Try
ViewContext.HttpContext.Response.Flush();
Istead of :
ViewContext.HttpContext.Response.Clear();

RequestMapping with more than one path element

I'm trying to write the simplest possible Spring application which uses more than one path element in a #RequestMapping. For example, /appcontext/blog/hello-world.html should work in the request mapping (obviously /appcontext is my application's context).
Can Spring do something like that? I have it working easily when it maps just one thing. For example:
#RequestMapping("hello-world")
works and will match /hello-world.do , /anything/hello-world.do , but my problem is, I'm trying to match only hello-world if it's in a /blog path, and whenever I use something like:
#RequestMapping("/blog/hello-world")
it doesn't ever trigger.
Server log for example:
INFO: Mapped "{[/blog/hello],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo()
That looks like it should work (and it's the only request mapping I have), but then:
WARNING: No mapping found for HTTP request with URI [/context/blog/hello.html] in DispatcherServlet with name 'dispatcher'
Can Spring do something like this? I don't want to put all my request mappings in /, because it's going to be a mess.
The only mapping I have gotten to work is:
#RequestMapping("/**")
From there, I could look at the HttpServletRequest object directly, but that seems to defeat the entire point of having #RequestMapping.
Here is my Controller:
#Controller
public class BlogController {
private static final Logger LOG = Logger.getLogger(BlogController.class.getName());
#RequestMapping("/blog/hello")
public String foo1() {
LOG.info("foo1");
return "nothing";
}
#RequestMapping("/blog/hello.html")
public String foo2() {
LOG.info("foo2");
return "nothing";
}
#RequestMapping("/blog/hello.*")
public String foo3() {
LOG.info("foo3");
return "nothing";
}
#RequestMapping("/blog/**")
public String foo4() {
LOG.info("foo4");
return "nothing";
}
#RequestMapping("/blog/{path}")
public String foo5(#PathVariable String path) {
LOG.info("foo5 " + path);
return "nothing";
}
// added this as a test - it's the only way that this controller works
#RequestMapping("/**")
public String foo6() {
LOG.info("foo6");
return "nothing";
}
}
If I don't have the foo6 mapping, nothing in this works at all, no matter what URLs I go to.
When I use that controller, this is what shows up in the server log:
INFO: Mapped "{[/blog/hello],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo1()
INFO: Mapped "{[/blog/hello.html],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo2()
INFO: Mapped "{[/blog/hello.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo3()
INFO: Mapped "{[/blog/**],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo4()
INFO: Mapped "{[/blog/{path}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo5(java.lang.String)
INFO: Mapped "{[/**],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo6()
But again, nothing ever triggers except foo6 if I put it in.
Thank you!
Edit: I have created an extremely simple project, which has only one class, the Controller, with one method, the RequestMapping. This project does nothing except not work. There is simply no way to get #RequestMapping to do anything other than work with a wildcard. This seems like a critical bug in Spring; all the documentations says that #RequestMapping does more than just map one wildcard.
It looks to me that the reason it's not mapping in the /blog path is that you're not using that path to access it.
According to the errors that you posted in the question above, you have defined/mapped:
/blog/hello
Whereas you are trying to access:
/context/blog/hello.html
i.e. You are prefixing the URI with "/context" and suffixing it with ".html". That's why it's not responding.
I would recommend trying to access the URI that you have mapped. However, you may also need to ensure that your application's root context is correct.
Note that by adding the ".html" suffix, you are not using the path that you defined. If you wish to use random suffixes such as that, then it is also possible to use wildrcards in your mappings. i.e. #RequestMapping(value = "/blog/hello**")
However, I would generally recommend against using wildcards if you can avoid it, as they are likely to throw up a few surprises when you add more mappings to your application.
Edit - I also just spotted that your controller is messing up those mappings even more. Just read the following mappings together:
#RequestMapping("/blog/hello")
#RequestMapping("/blog/hello.html")
#RequestMapping("/blog/hello.*")
Your mappings are clashing with each other. The first mapping in that list is a subset of the others, so it will be used for any URLs that match any of those mappings. i.e. The second 2 are redundant. You could potentially fix that by putting the 'bare' /blog/hello after the the other 2, so that the more specific mappings are picked up first, however, relying on the order in which the methods are written seems like asking for trouble to me.
Figured it out. The servlet-mapping chops off part of the path! The servlet-mapping basically creates a mini-context. I didn't know it did that, and it's not intuitively obvious, but that's what's happening.

Spring mvc controller null return handler

#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public List<Country> getListOfCountries() {
return countryService.listAll();
}
It displays a json view of the object but if the service return null, then I want to display an error message, Any suggestions pls?
First of all, even if this does not directly answer the question, your objects should never ever return null instead of empty collections - you can find the reasoning in Effective Java 2nd Edition, Item 43 / p.201
So, if the situation when no countries were found is normal it must be processed by the client JS code that will check the count and display the respective message.
If something has gone wrong you can throw an exception(as Biju has pointed out +1) - I believe that it's the service who should throw the exception because it knows the reason why it happened, and not to return null anyway.
I'd like to add that in Spring 3.2(in pre Spring 3.2 returning response body is complicated) you can set an #ExceptionHandler that will both return JSON and set the HTTP status code which can be later processed by the client. I think that returning a custom JSON response with some error code is most optimal here.
#RequestMapping("/test")
#ResponseBody
public List<Country> getListOfCountries() {
//assuming that your service throws new NoCountriesFoundException();
//when something goes wrong
return countryService.listAll();
}
#ExceptionHandler(NoCountriesFoundException.class)
ResponseEntity<String> test() {
return new ResponseEntity<String>(
"We are sorry, our server does not know any countries yet.",
HttpStatus.I_AM_A_TEAPOT );
}
Then in the JS code, you can do specific processing depending on the returned status code.
Also, to avoid declaration of the same #ExceptionHandler in different controllers, in Spring 3.2 you can put #ExceptionHandler inside a #ControllerAdvice annotated class.
For details, see http://static.springsource.org/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers and http://www.springsource.org/node/3738 for 3.2 specific things
You have a couple of options I think:
If you return a null back, it will be returned as an empty string "", you can probably look for that and handle it.
Return a wrapper type on top of your list, this way if the wrapped list is null something like this will be returned back to the client {"countries":null} which can be more easily handled at the javascript end.
Throw an exception, which will propagate as a 500 status code back to the client, you can then have an error handler on the javascript side to handle this scenario.

ASP.NET MVC3 app creating bad route value

OK, this may just me being ignorant, but I have the following route in my MVC3 application:
routes.MapRoute("Directory","{aid}/{controller}/{action}/{year}/{quarter}",
new { aid = "sf", controller = "Lobbyist", action = "Index",
year = CurrentYear(), quarter = CurrentQuarter() });
In my Global.asax.cs, I have these two methods:
public static int CurrentQuarter()
{
int quarter = 0;
//...use some internal business logic to determine the value of
//'quarter' based on the current date...
return quarter;
}
public static int CurrentYear()
{
return DateTime.Now.Year;
}
This code works great almost all the time. At one point in time, in our production environment (running IIS7), the route value for CurrentQuarter() became a value of zero, when it should have been 1, 2, 3, or 4. It works just fine in production except for that one point in time. An IISRESET 'fixed' the problem.
What I know:
At the time CurrentQuarter() was failing, CurrentYear() was still
returning correctly
The CurrentQuarter() method was not throwing an
exception which would have prevented setting the 'quarter' variable
The business logic which drives the CurrentQuarter() method works
for every date between DateTime.MinValue and DateTime.MaxValue
My question really gets down to is:
Is it BAD to call static methods to generate route values?
Is there a potential for the application to 'forget' the result of the static method, and cause it to return a garbage value? Could an application pool recycling cause this?
I'm sort of grasping at straws here!
Thanks for any advice.
I would not call static values here. I completely disagree with Igor above. Its not standard and is hard to track down where these values are coming from to someone that doesn't know the app. Call it either from your controller, or even better yet - a service layer (ie business logic) your controller calls to that gets this value.
A routes purpose is not to call a business method.
On the second question, if there is an app pool recycle, the value will simply be reset. However if multiple threads are calling into this method and potentially changing the value in the same method I would implement some locking in there to prevent updates from overlapping.
You should make the route values year and quarter optional, and provide default values for them in the Action method. I think this makes everything cleaner, and easier to maintain.
public class LobbyistController
{
public ActionResult Index(int? year, int? quarter)
{
if (!currentYear.HasValue)
{
currentYear = GetCurrentYear();
}
if (!currentQuarter.HasValue)
{
currentQuarter = GetCurrentQuarter();
}
// the rest
}
}

Resources