handle Exception in Spring Web Flow - spring

Hello Friends Iam trying to handle
org.springframework.webflow.execution.repository.snapshot.SnapshotNotFoundException
this exception but iam failed to do so.
In this way i handle SnapshotNotFoundException.
<transition on-exception="org.springframework.webflow.execution.repository.snapshot.SnapshotNotFoundException"
to="exceptionHandler" />

That declarative Exception handling does not seem to work for internal Web Flow exceptions. For this particular case, we had to implement a custom FlowHandler.handleException().
Something like:
public class CustomFlowHandler extends AbstractFlowHandler
{
#Override
public String handleException(FlowException e, HttpServletRequest request,
HttpServletResponse response)
{
if (e instanceof FlowExecutionRestorationFailureException)
{
if (e.getCause() instanceof SnapshotNotFoundException)
{
// TODO return the desired location string. See javadoc for options
return "serverRelative:/missingSnapshot.html";
}
}
return super.handleException(e, request, response);
}
}
And in Spring configuration file:
<!-- custom flow handler -->
<bean name="your-flow-name" class="yourpackage.CustomFlowHandler"/>

Related

Package/Endpoint/Controller Layer Exception Handling Design

So here is my requirement to handle component/package-specific exceptions. for example for package A, BAD Request should return spring default bad request-response, but for package B it should return custom response.
You can specify the behaviour for specific exceptions thrown from your code using an #ExceptionHandler. Also, you can limit your exception handlers to specific packages:
#ControllerAdvice(package = "com.example.b")
public class PackageBErrorHandler {
#ResponseStatus(BAD_REQUEST)
#ExceptionHandler
#ResponseBody
public ErrorDto handleValidationError(ConstraintValidationException e) {
return ...; //build your custom response here
}
}

How to pass and handle Exceptions through HTTP responses in Spring?

I have a Client and Server module in my Spring project running on separate ports. The Client module makes a POST request to the Server via a RestTemplate. The Server-Module throws a custom Exception with a custom error-message. Currently, in my Project, the Server has a RestControllerAdvice Class that handles such exceptions as follows:
#RestControllerAdvice
public class AppRestControllerAdvice {
#ExceptionHandler(ApiException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public MessageData handle(ApiException e) {
MessageData data = new MessageData();
data.setMessage(e.getMessage());
return data;
}
}
On the Client side, the following method catches the Response from the Server.
#RestControllerAdvice
public class AppRestControllerAdvice {
#ExceptionHandler(ApiException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public MessageData handle(ApiException e) {
MessageData data = new MessageData();
data.setMessage(e.getMessage());
return data;
}
#ExceptionHandler(Throwable.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public MessageData handle(Throwable e) {
MessageData data = new MessageData();
data.setMessage("UNKNOWN ERROR- " + e.getMessage());
e.printStackTrace();
return data;
}
}
Whenever the Exception is thrown on the server, here is what I receive on the Client
{
"message": "UNKNOWN ERROR- org.springframework.web.client.HttpClientErrorException: 400 Bad Request"
}
My question is, how do I retrieve the Custom Exception message that originated on the Server?
Also, why isn't the correct RestControllerAdvice module on the Client side picking up the error? (The INTERNAL_SERVER_ERROR method catches the error instead of the BAD_REQUEST method.)
My question is, how do I retrieve the Custom Exception message that originated on the Server?
To retrieve the orignal exception message you have to use dedicated ResponseErrorHandler that is capable of extracting that information, rather than using the default one (DefaultResponseErrorHandler - which I assume you use because of the message you got - org.springframework.web.client.HttpClientErrorException: 400 Bad Request).
Create:
public class CustomerResponseErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse httpResponse) throws IOException {
// here you have access to the response's body which potentially contains the exception message you are interested in
// simply extract it if possible and throw an exception with that message
// in other case you can simply call `super.handlerError()` - do whatever suits you
}
}
Then use it with your RestTemplate:
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
          .errorHandler(new CustomerResponseErrorHandler())
          .build();
}
}
Also, why isn't the correct RestControllerAdvice module on the Client side picking up the error? (The INTERNAL_SERVER_ERROR method catches the error instead of the BAD_REQUEST method.)
The correct method is executed - your RestTemplate at the moment is throwing HttpClientErrorException which is not an ApiException. It is a Throwable though.

Call another method after Spring MVC handler returns

I have a requirement where I need to return some status/Long value from a rest controller and then execute code to send push notification.
#RequestMapping(value="/create")
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
Can some one please tell me how to achieve this? Is it possible to use Spring AOP for this? I don't think thread will guaranteed execution of sendPushNotifiction method only after return. So what are the ways to achieve this effectively?
Thanks in advance
I think it might be a good use case for asynchronous processing. Spring has good support for it. Precisely, you need to
Annotate sendPushNotifiction with #Async.
Annotate some configuration class with #EnableAsync.
Call sendPushNotifiction() before the return statement. The execution flow will not wait for sendPushNotifiction to finish.
If it doesn't work, try coding sendPushNotifiction in a separate service.
Create another method which first calls the createTicket() method and then calls the sendPushNotifiction(). That will do the job. This the simplest way in my humble opinion.
createTicket()is called by spring.You can't call it directly.You can use org.springframework.web.servlet.HandlerInterceptor.Just call your sendPushNotifiction() method from postHandle() or afterCompletion() method of
your HandlerInterceptor
package com.sample.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class NotifictionHandlerInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//do nothing
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//call your method here
//call sendPushNotifiction()
}
}
And register you handler in spring-mvc context
<mvc:interceptors>
<bean class="com.sample.NotifictionHandlerInterceptor" />
</mvc:interceptors>
You can call like that:
#RequestMapping(value="/create")
public void create(){
createTicket();
sendPushNotifiction();
}
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
i agree with youngHobbit solution where you can do like below wh
#RequestMapping(value="/create")
public String entryMethod() throws InterruptedException {
String response = createTicket();
sendPushNotifiction();
return response ;
}
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
Though another solution can be to forward/redirect the request to another method once you are done with first one. But take the first approach if it solves your purpose as its simple,clear and readable
AOP is for basically dealing cross cutting concerns which you want to handle across application, should not be used for very specific purpose like this. Why to introduce extra complexity when
Another way is to postpone the execution of sendPushNotification() to some thread / thread pool. Before the return, use a queue to enqueue the processing, then in your thread dequeue and process.
However, you should take care to link your requests to the real caller and take care of failures, etc.
Web is full of examples. Look for java.util.concurrent examples, executors, ...
The HandlerInterceptor is the solution, but the code get a little bit more complex than expected. Here's a code suggestion to make it simpler by putting the whole solution in a single class:
#RequestMapping(value = "/create")
public String createTicket() throws InterruptedException {
String ticket = "ticket created";
result.set(ticket); // Save the ticket to be used after response
return ticket;
}
public void sendPushNotifiction(String ticket) throws InterruptedException {
System.out.println("Sent push notification successfully!!");
}
private static final ThreadLocal<String> result = new ThreadLocal<String>();
#Bean
public MappedInterceptor interceptor() {
return new MappedInterceptor(Arrays.array("/create"), new HandlerInterceptor() {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object and clean for the next request
String ticket = result.get();
result.set(null);
// Execute after response
sendPushNotifiction(ticket);
}
});
}

GWT does not work with Spring REST service

I wrote a Spring REST application. I tested it with curl command and it worked truly.
In another GWT Ajax application I have an RequestBuilder object that it does not work with my Spring Rest: after calling sendRequest method, the event onResponseReceived is fired but the getText method returns an empty string.
this is a part of my spring servlet.xml configuration file
<bean id="jsonmembertemplate"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
<property name="contentType" value="text/javascript;charset=UTF-8"/>
<property name="disableCaching" value="false"/>
</bean>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
and a part of my controller class
#RequestMapping(method = RequestMethod.GET, value="/member/get/{memberid}")
public String getMember(Model model, #PathVariable("memberid") int id, HttpServletResponse response) {
model.addAttribute("member", memberDao.get(id));
return "jsonmembertemplate";
}
and gwt code
private RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "http://localhost:8080/depna-nat-server/member/get/1?");
try {
rb.setHeader("Content-Type", "text/javascript;charset=UTF-8");
rb.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
Window.alert(Integer.toString(response.getStatusCode()));
Window.alert(response.getStatusText());
Window.alert(Integer.toString(response.getText().length()));
area.setText(response.getText());
}
#Override
public void onError(Request request, Throwable exception) {
Window.alert("fail");
}
});
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I have a couple of gwt applications working with json and xml rest services offered by spring, we use spring instead of gwt (rpc or rf) because these services are offered to 3party apps as well.
I started my first project with RequestBuilder and we dind't have any problem, so maybe you have some issue in your code, could you inspect the traffic and post the errors you have?
If you are running a cross-domain issue (statusCode=0 normally means it) , add a filter to your servlet container, take a look to this document.
I finally opted to use gwtquery-ajax and gquery-data-binding because it made really easy to consume these services and to map them to java objects.

Session management in gwt

I am using GWT for my client side application. However, I am not sure how I can handle session management. The GWT application resides on one page, all server calls are done via AJAX. If a session expires on the server. let's assume the user didn't close the browser, and sending some request to server using RPC, how could my server notify the application that the session has expired and that the client side portion should show the login screen again?My sample code :
ContactDataServiceAsync contactDataService = GWT
.create(ContactDataService.class);
((ServiceDefTarget) contactDataService).setServiceEntryPoint(GWT
.getModuleBaseURL()
+ "contactDatas");
contactDataService.getContact(2,
new AsyncCallback<ContactData>() {
public void onFailure(Throwable caught) {
//code to show error if problem in connection or redirect to login page
}
public void onSuccess(ContactData result) {
displayContact(result);
}
});
If session expires only it has to show login screen, otherwise it wants to show some error using Window.alert().
How to do this and what are all the codes needed in server side and client side?
You could have the server throw an AuthenticationException to the client in case the user has been logged out.
This will be catched in the callbacks onFailure method, which then can redirect the user to the login-page.
Edit:
AuthenticationException is not a standard exception of course, i was just making an example. It might be best to stick with the standard exceptions.
To try if you caught an specific exception you could use the instanceof operator
public void onFailure(Throwable e) {
if(e instanceof AuthenticationException) {
redirecttoLogin();
}
else {
showError(),
}
}
This does not directly apply to those using RPC, but for those of you who are not using RPC, you should send a HTTP 401 from the server. Then you can check that status code in your RequestBuilder callback.
Client: All Callbacks extend a Abstract Callback where you implement the onFailur()
public abstract class AbstrCallback<T> implements AsyncCallback<T> {
#Override
public void onFailure(Throwable caught) {
//SessionData Expired Redirect
if (caught.getMessage().equals("500 " + YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN)) {
Window.Location.assign(ConfigStatic.LOGIN_PAGE);
}
// else{}: Other Error, if you want you could log it on the client
}
}
Server: All your ServiceImplementations extend AbstractServicesImpl where you have access to your SessionData. Override onBeforeRequestDeserialized(String serializedRequest) and check the SessionData there. If the SessionData has expire then write a spacific error message to the client. This error message is getting checkt in your AbstrCallback and redirect to the Login Page.
public abstract class AbstractServicesImpl extends RemoteServiceServlet {
protected ServerSessionData sessionData;
#Override
protected void onBeforeRequestDeserialized(String serializedRequest) {
sessionData = getYourSessionDataHere()
if (this.sessionData == null){
// Write error to the client, just copy paste
this.getThreadLocalResponse().reset();
ServletContext servletContext = this.getServletContext();
HttpServletResponse response = this.getThreadLocalResponse();
try {
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
try {
response.getOutputStream().write(
ConfigStatic.ERROR_MESSAGE_NOT_LOGGED_IN.getBytes("UTF-8"));
response.flushBuffer();
} catch (IllegalStateException e) {
// Handle the (unexpected) case where getWriter() was previously used
response.getWriter().write(YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN);
response.flushBuffer();
}
} catch (IOException ex) {
servletContext.log(
"respondWithUnexpectedFailure failed while sending the previous failure to the client",
ex);
}
//Throw Exception to stop the execution of the Servlet
throw new NullPointerException();
}
}
}
In Addition you can also Override doUnexpectedFailure(Throwable t) to avoid logging the thrown NullPointerException.
#Override
protected void doUnexpectedFailure(Throwable t) {
if (this.sessionData != null) {
super.doUnexpectedFailure(t);
}
}

Resources