1

I am developing a webapp that provides a number of REST endpoints with Google Sitebricks. To minimize duplicate/similar code I would like to configure sitebricks to respond with a consistent Reply object every time the code executed in the REST endpoints throws an exception.

Instead of handling the exceptions and creating a custom JSON response in each endpoint I want that sitebricks itself catches the exception and returns something like:

{
  statusCode: 123,
  message: "this could contain Exception.getMessage()",
  stacktrace: "this could contain the full stacktrace"
}

Sitebricks would then be responsible to create the above structure and fill in the status code and other fields e.g. based on an annotation.

  • Do I have to build this myself or did somebody else already do that? Maybe there even is a way to do this with Sitebricks itself?
  • Is there an equivalent to Jersey's ExceptionMapper interface?
Ingo
  • 1,552
  • 10
  • 31

2 Answers2

0

Not exactly answering your question but what I did to manage errors is the following.

In the parent class of all my REST endpoints, i've declared the following method :

protected Reply<?> error(String errorCode) {
    logger.error(errorCode);
    return Reply.with(new ErrorJSONReply(errorCode)).as(Json.class).headers(headers()).type("application/json; charset=utf-8");
}

Then in all my endpoints I'm catching exceptions and use this method to reply a generic error.

Hope that helps.

Regards

Thomas
  • 1,410
  • 10
  • 24
0

You can use Guice's AOP goodness to bind a method interceptor to catch and serialize exceptions to JSON...

public class ReplyInterceptor implements MethodInterceptor {

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    @BindingAnnotation
    public @interface HandleExceptionsAndReply {
    }


    public ReplyInterceptor() {
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        try {
            return methodInvocation.proceed();
        } catch (Throwable e) {
            return handleException(e);
        }
    }

    private Object handleException(Throwable e) {
        Throwable cause = getCause(e);
        return Reply.with(cause).as(Json.class);
    }


    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    private Throwable getCause(Throwable e) {
        // org.apache.commons.lang3.exception.ExceptionUtils
        Throwable rootCause = ExceptionUtils.getRootCause(e);
        return rootCause == null ? e : rootCause;
    }
}

Bind it...

bindInterceptor(
        Matchers.any(),
        Matchers.annotatedWith(ReplyInterceptor.HandleExceptionsAndReply.class),
        new ReplyInterceptor(getProvider(ResponseBuilder.class))
);

// OR bind to request method annotations...

bindInterceptor(
        Matchers.any(),
        Matchers.annotatedWith(Get.class),
        new ReplyInterceptor(getProvider(ResponseBuilder.class))
);

Use it...

@At("/foo/:id")
@Get
@ReplyInterceptor.HandleExceptionsAndReply
public Reply<ApiResponse<Foo>> readFoo(@Named("id") String id) {
     // fetch foo and maybe throw an exception
     // ...        
}

Ref: https://code.google.com/p/google-guice/wiki/AOP

wmluke
  • 309
  • 1
  • 6