Stripes Interceptor for Saving Error Messages on Redirect

Maybe I’m repeating my self but I’ll say again: Stripes is a great framework! It has everything you’d expect from a web presentation framework and I really didn’t hit a single bug. However, one thing was driving me nuts and was not working in accordance with my expectations…

Usually, when I want to show some error message to user, I add it as a global error to the current context:

1
getContext().getValidationErrors().addGlobalError(...);

In some cases this is followed by a RedirectResolution to a different action bean. The problem is error messages will be lost because of the redirection. If I were using messages instead of errors Stripes would handle it automatically (saving messages in the flash context, adding a special parameter to the redirect URL that would be used to retrieve the messages later). According to someĀ  mailing list posts, this behavior is intentional. Well, I understand part of the reasoning but I don’t see any problem with passing global errors between contexts.

I don’t want to show my errors as messages and I don’t want to think about it any more. So, here’s a simple Stripes interceptor I wrote to workaround this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Intercepts(LifecycleStage.EventHandling)
public class ErrorMessageInterceptor implements Interceptor {

  private static final String CTX_KEY = "MY_GLOBAL_ERRORS";

  @Override
  public Resolution intercept(ExecutionContext ctx) throws Exception {

    List<ValidationError> globalErrors = (List<ValidationError>) ctx.getActionBeanContext().getRequest().getAttribute(CTX_KEY);
    if(globalErrors != null) {
      for (ValidationError globalError : globalErrors) {
        ValidationErrors errors = ctx.getActionBeanContext().getValidationErrors();
        errors.addGlobalError(globalError);
      }
      ctx.getActionBeanContext().getRequest().removeAttribute(CTX_KEY);
    }

    Resolution resolution = ctx.proceed();

    ValidationErrors errors = ctx.getActionBeanContext().getValidationErrors();
    globalErrors = errors.get(ValidationErrors.GLOBAL_ERROR);
    if(globalErrors != null && globalErrors.size() > 0 && resolution instanceof RedirectResolution) {
      FlashScope scope = FlashScope.getCurrent(ctx.getActionBeanContext().getRequest(), true);
      scope.put(CTX_KEY, globalErrors);
    }

    return resolution;
  }
}

(Obviously I dropped import clauses but you’ll know your way around it.)

In short:

  • Line 1: Attaches interceptor to event handling stage.

  • Lines 20-25: After event executes (in line 18), if there are global errors and resolution is RedirectResolution, save errors in flash context with our private key.

  • Lines 9-16: Before the next event executes (assuming user is back with the redirected request), we lookup for our key but this time in request context (as Stripes will move this automatically from the flash). If there are errors found, inject them to the current context.

Again, this is working for me but I hope it will be of use to someone else too. Feel free to drop me a note if you have any thoughts about it.

Comments