How to handle generic Exception in spring - spring-mvc

I am working on a spring project which has several classes. Now the code in that project is not up to the standard because of which there are no try catch blocks defined in any of the classes.
I have the following mapping in my web.xml
<error-page>
<exception-code>404</exception-type>
<location>/error.do</location>
</error-page>
the /error.do is mapped to a controller from where its forward to a generic error view . Now ,will it be possible to get the stacktrace of my exception. My only requirement is to get the exception details in that error handler like -- where exception originated like class name, method name and exception message which i felt will be available in stack trace.
Any idea how to proceed with this problem statement?

Yes you can do it Spring provides #ExceptionHandler annotation.So in your controller write one method as :
#ExceptionHandler(YourException.class)
public ModelAndView handleYourException(YourException ex, HttpServletRequest request) {
mav = new ModelAndView();
mav.addObject("exception", exception);
mav.setViewName("YourException Page");
return mav;
}
Hope you got my point.

Related

Spring mockMvc throws error when using ExceptionHandler

I am using SpringMockMvc and in my controller I have #ExceptionHandler. When calling post request, I am getting the below error.
Failed to invoke #ExceptionHandler method: public org.springframework.http.ResponseEntity<com.xx.xxx> com.xx.xx.handleException(java.lang.Throwable,org.eclipse.jetty.server.Request)
java.lang.IllegalStateException: Current request is not of type [org.eclipse.jetty.server.Request]: org.springframework.mock.web.MockHttpServletRequest#47fac1bd
at org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver.resolveArgument(ServletRequestMethodArgumentResolver.java:97)
I am not sure why #ExceptionHandler cannot handle if the request is of type org.springframework.mock.web.MockHttpServletRequest
That could never work, simply because org.springframework.mock.web.MockHttpServletRequest is not a sub-type of org.eclipse.jetty.server.Request. Thus, it is impossible for Spring to provide an instance of MockHttpServletRequest for a parameter of type org.eclipse.jetty.server.Request.
You'll need to change the type of the second parameter in your handleException() method to javax.servlet.http.HttpServletRequest.

Liferay: how to get the current login user details in servlet?

I'm completely new to Liferay. I have configured Orbeon Forms in Liferay by using the Proxy Portlet, finally I created an Orbeon form and sent the form data to a demo portlet (custom portlet). In the portlet I have created a servlet. If user save the orbeon form data then my servlet getting called and I'm able to get the form data. Now I need to get the current user name or userid in the servlet.
In form builder I have send the orbeon form data to my servlet.
properties-local.xml
<property
as="xs:string"
name="oxf.fr.detail.process.send.*.*"
value='require-valid
then send(uri = "http://localhost:9090/FRunner-portlet/html/jsp/formData.jsp?username={xxf:get-request-header('Orbeon-Username')}", method="POST", content="metadata")
then success-message("save-success")
recover error-message("database-error")'/>
If I tried the above code I got the following errors,
SEVERE: Exception sending context initialized event to listener instance of class org.orbeon.oxf.webapp.OrbeonServletContextListener
javax.servlet.ServletException: org.orbeon.oxf.common.ValidationException: line 80, column 122 of oxf:/config/properties-local.xml: Fatal error: Element type "property" must be followed by either attribute specifications, ">" or "/>".
at org.orbeon.oxf.webapp.OrbeonServletContextListener$$anonfun$contextInitialized$2.apply(OrbeonServletContextListener.scala:39)
at org.orbeon.oxf.webapp.OrbeonServletContextListener$$anonfun$contextInitialized$2.apply(OrbeonServletContextListener.scala:39)
at org.orbeon.oxf.util.ScalaUtils$.withRootException(ScalaUtils.scala:87)
at org.orbeon.oxf.webapp.OrbeonServletContextListener.contextInitialized(OrbeonServletContextListener.scala:39)
Caused by: org.orbeon.oxf.common.ValidationException: line 80, column 122 of oxf:/config/properties-local.xml: Fatal error: Element type "property" must be followed by either attribute specifications, ">" or "/>".
at org.orbeon.oxf.xml.XMLParsing$ErrorHandler.fatalError(XMLParsing.java:215)
at orbeon.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source)
at orbeon.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at orbeon.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at orbeon.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at orbeon.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source)
SEVERE: Exception sending context destroyed event to listener instance of class org.orbeon.oxf.webapp.OrbeonServletContextListener
javax.servlet.ServletException: java.lang.NullPointerException
at org.orbeon.oxf.webapp.OrbeonServletContextListener$$anonfun$contextDestroyed$2.apply(OrbeonServletContextListener.scala:44)
at org.orbeon.oxf.webapp.OrbeonServletContextListener$$anonfun$contextDestroyed$2.apply(OrbeonServletContextListener.scala:44)
at org.orbeon.oxf.util.ScalaUtils$.withRootException(ScalaUtils.scala:87)
at org.orbeon.oxf.webapp.OrbeonServletContextListener.contextDestroyed(OrbeonServletContextListener.scala:44)
at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4819)
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5466)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160)
Caused by: java.lang.NullPointerException
at org.orbeon.oxf.pipeline.InitUtils$.org$orbeon$oxf$pipeline$InitUtils$$fromProperty$1(InitUtils.scala:195)
at org.orbeon.oxf.pipeline.InitUtils$.processorDefinitions$lzycompute(InitUtils.scala:196)
at org.orbeon.oxf.pipeline.InitUtils$.processorDefinitions(InitUtils.scala:179)
at org.orbeon.oxf.webapp.Orbeon$.initialize(Orbeon.scala:84)
at org.orbeon.oxf.webapp.OrbeonWebApp$$anonfun$1.apply(WebAppContext.scala:117)
at org.orbeon.oxf.webapp.OrbeonWebApp$$anonfun$1.apply(WebAppContext.scala:117)
at scala.collection.mutable.MapLike$class.getOrElseUpdate(MapLike.scala:189)
at org.orbeon.oxf.webapp.ParametersAndAttributes$$anon$1.getOrElseUpdate(WebAppContext.scala:93)
at org.orbeon.oxf.webapp.OrbeonWebApp$class.$init$(WebAppContext.scala:117)
Update
xxf:get-request-header('orbeon-liferay-user-email')
With the above statement I am able to get the liferay login user mail id. Now I need to pass this username to my portlet as a parameter. Can you please let me know what is the procedure to pass the mailid to my portlet. I tried in different ways but it is not happen. Please suggest me something to send the liferay user mail id to my portlet.
FormData Servlet code
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
DataInputStream in = new DataInputStream (request.getInputStream());
StringBuffer buffer = new StringBuffer();
int value;
while ((value=in.read()) != -1) {
buffer.append((char)value);
}
String formData = buffer.toString();
System.out.println("Form Data==========>"+ formData);
} catch (Exception e) {
System.out.println("ERROR2=====>"+e);
}
}
How to get the current user details when servlet getting called?
One way is to explicitly pass it to the URL of the send action, for example:
uri = ".../FormData?username={xxf:get-request-header('Orbeon-Username')}"
In Orbeon Forms 4.9, there is a new xxf:username() function which is more direct.
On the servlet side, you can retrieve a URL parameter using:
request.getParameter("username")

How to customize #RequestParam error 400 response in Spring MVC

Is there a way to customize what gets displayed when a required #RequestParam is not sent to the request handler? I always get HTTP Status 400 with a description "The request sent by the client was syntactically incorrect ()." in this case.
Yes, there is a way you should catch MissingServletRequestParameterException
You can do it in several ways:
1)
#ExceptionHandler(MissingServletRequestParameterException.class)
public String handleMyException(Exception exception) {
return "yourErrorViewName";
}
2)
<error-page>
<exception-type>org.springframework.web.bind.MissingServletRequestParameterException</exception-type>
<location>/WEB-INF/pages/myError.jsp</location>
</error-page>
Hope it helps.
How I solved my problem:
#ResponseBody
#ExceptionHandler(MissingServletRequestParameterException.class)
public Object missingParamterHandler(Exception exception) {
// exception handle while specified arguments are not available requested service only. it handle when request is as api json service
return new HashMap() {{ put("result", "failed"); put("type", "required_parameter_missing");}};
}

Spring MVC 3: How to provide dynamic content to error page for HTTP 404 errors?

What I want:
I want to provide a model to the HTTP 404 error page. Instead of writing a static error Page, which is specified within web.xml, I want to use an
exception controller, which handles HTTP 404 errors.
What I did:
Removed error page tag from web.xml:
<error-page>
<error-code>404</error-code>
<location>/httpError.jsp</location>
</error-page>
and implemented the following exception handler methods inside my AbstractController class:
#ExceptionHandler(NoSuchRequestHandlingMethodException.class)
public ModelAndView handleNoSuchRequestException(NoSuchRequestHandlingMethodException ex) {
ModelMap model = new ModelMap();
model.addAttribute("modelkey", "modelvalue");
return new ModelAndView("/http404Error", model);
}
#ExceptionHandler(NullPointerException.class)
public ModelAndView handleAllExceptions(NullPointerException e) {
ModelMap model = new ModelMap();
model.addAttribute("modelkey", "modelvalue");
return new ModelAndView("/exceptionError", model);
}
What is does:
It works find for exceptions, but not for HTTP error code status 404. It seems like HTTP 404 errors are handled by DispatcherServlet by default. Is it possible to change this behaviour?
And how can I catch 404 errors in my exception handler?
If you want to get some dynamic content in your 404 page or any other error page, map the page to a controller in your spring context.
For example, declare a controller named "404.htm" and try to request the page /404.htm to insure that it's working fine,
then in your web.xml write the following :
<error-page>
<error-code>404</error-code>
<location>/404.htm</location>
</error-page>
Try with this url http://blog.codeleak.pl/2013/04/how-to-custom-error-pages-in-tomcat.html
Explains how to create a controller to get the error and put parameters to whow them in the .jsp.

Handling Exceptions like ServletRequestBindingException in Spring rather than Servlet Container

I am using springmvc for a REST project and whenever the client calls a rest resource with the wrong HTTP method, a servletrequestbindingexception is thrown. I cannot handle these exceptions with a #ExceptionHandler in the controller, as it happens not within the handler method but in the spring mapping layer.
Currently I declared a web.xml exception handling, this works:
<error-page>
<exception-type>org.springframework.web.bind.ServletRequestBindingException</exception-type>
<location>/servletRequestBindingException.jsp</location>
</error-page>
<error-page>
<error-code>405</error-code>
<location>/methodNotSupported.jsp</location>
</error-page>
I'd rather use spring exception handling though. For example I'd like to create a dynamic response based on teh incoming Accept header, so either writing out json or xml for a rest exception for example. The best would be to return an object from this handler that would automatically be converted to json or xml just like a normal dto returned from a handler.
Is there a way to catch these lower level mapping exceptions?
You can't use #ExceptionHandler (since as you say, this is for dealing exceptions thrown from within the handler code), but you can still use the HandlerExceptionResolver framework to do this.
By default, DispatcherServlet registers an instance of DefaultHandlerExceptionResolver:
Default implementation of the HandlerExceptionResolver interface that resolves standard Spring exceptions and translates them to corresponding HTTP status codes.
The generation of the HTTP 405 is actually handled in this class, by catching HttpRequestMethodNotSupportedException thrown by the handler-mapping code.
So if you want to handle this exception differently, you can provide your own implementation of HandlerExceptionResolver. It's probably easiest to subclass DefaultHandlerExceptionResolver and override the handleHttpRequestMethodNotSupported method, returning your ModelAndView from there.
Be careful to include the default exception resolvers if you include your own. If you are using annotated #Exception handlers you need to explicitly load these or they will no longer function.
In this case, FooBarHandlerExceptionResolver extends DefaultHandlerExceptionResolver and provides a method that the default resolver doesn't cover. This lets FooBarHandlerExceptionResolver handle class-level exceptions that I couldn't catch with annotated #Exception handler methods.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="order" value="1"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver" >
<property name="order" value="2"/>
</bean>
<bean class="com.company.package.foo.FooBarHandlerExceptionResolver">
<property name="order" value="3"/>
</bean>
Here is the exception resolver
public class FooBarHandlerExceptionResolver extends DefaultHandlerExceptionResolver {
#Override
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
try {
if (ex instanceof UnsatisfiedServletRequestParameterException) {
return handleUnsatisfiedServletRequestParameter((UnsatisfiedServletRequestParameterException) ex, request, response,
handler);
}else {
super.doResolveException(request,response,handler,ex);
}
}
catch(Exception handlerException){
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
return null;
}
protected ModelAndView handleUnsatisfiedServletRequestParameter(UnsatisfiedServletRequestParameterException ex,
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
logger.warn(ex.getMessage());
return new ModelAndView("blank", new ModelMap("reason", ex.getMessage()));
}
}

Resources