killbill-uncached

jaxrs: suppress stacktrace in response by default The client

10/16/2014 7:35:26 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
index a009eb5..181fa6d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BillingExceptionJson.java
@@ -54,12 +54,13 @@ public class BillingExceptionJson {
         this.stackTrace = stackTrace;
     }
 
-    public BillingExceptionJson(final Exception exception) {
+    public BillingExceptionJson(final Exception exception, final boolean withStackTrace) {
         this(exception.getClass().getName(),
              exception instanceof BillingExceptionBase ? ((BillingExceptionBase) exception).getCode() : null,
              exception.getLocalizedMessage(),
              exception.getCause() == null ? null : exception.getCause().getClass().getName(),
              exception.getCause() == null ? null : exception.getCause().getLocalizedMessage(),
+             !withStackTrace ? ImmutableList.<StackTraceElementJson>of() :
              Lists.<StackTraceElement, StackTraceElementJson>transform(ImmutableList.<StackTraceElement>copyOf(exception.getStackTrace()),
                                                                        new Function<StackTraceElement, StackTraceElementJson>() {
                                                                            @Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
index 7e32c1d..047d76e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/mappers/ExceptionMapperBase.java
@@ -48,6 +48,8 @@ public abstract class ExceptionMapperBase {
     private static final Logger log = LoggerFactory.getLogger(ExceptionMapperBase.class);
     private static final ObjectMapper mapper = new ObjectMapper();
 
+    private static final String QUERY_WITH_STACK_TRACE = "withStackTrace";
+
     protected Response fallback(final Exception exception, final UriInfo uriInfo) {
         if (exception.getCause() == null) {
             return buildBadRequestResponse(exception, uriInfo);
@@ -114,7 +116,7 @@ public abstract class ExceptionMapperBase {
         log.warn("Conflicting request", e);
 
         final Response.ResponseBuilder responseBuilder = Response.status(Status.CONFLICT);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
@@ -123,7 +125,7 @@ public abstract class ExceptionMapperBase {
         log.info("Not found", e);
 
         final Response.ResponseBuilder responseBuilder = Response.status(Status.NOT_FOUND);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
@@ -132,7 +134,7 @@ public abstract class ExceptionMapperBase {
         log.warn("Bad request", e);
 
         final Response.ResponseBuilder responseBuilder = Response.status(Status.BAD_REQUEST);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
@@ -142,7 +144,7 @@ public abstract class ExceptionMapperBase {
 
         // TODO Forbidden?
         final Response.ResponseBuilder responseBuilder = Response.status(Status.UNAUTHORIZED);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
@@ -151,23 +153,24 @@ public abstract class ExceptionMapperBase {
         log.warn("Internal error", e);
 
         final Response.ResponseBuilder responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
     protected Response buildPluginTimeoutResponse(final Exception e, final UriInfo uriInfo) {
         final Response.ResponseBuilder responseBuilder = Response.status(Status.ACCEPTED);
-        serializeException(e, responseBuilder);
+        serializeException(e, uriInfo, responseBuilder);
         return responseBuilder.build();
     }
 
-    private void serializeException(final Exception e, final Response.ResponseBuilder responseBuilder) {
-        final BillingExceptionJson billingExceptionJson = new BillingExceptionJson(e);
+    private void serializeException(final Exception e, final UriInfo uriInfo, final Response.ResponseBuilder responseBuilder) {
+        final boolean withStackTrace = uriInfo.getQueryParameters() != null && "true".equals(uriInfo.getQueryParameters().getFirst(QUERY_WITH_STACK_TRACE));
+        final BillingExceptionJson billingExceptionJson = new BillingExceptionJson(e, withStackTrace);
 
         try {
             final String billingExceptionJsonAsString = mapper.writeValueAsString(billingExceptionJson);
             responseBuilder.entity(billingExceptionJsonAsString).type(MediaType.APPLICATION_JSON);
-        } catch (JsonProcessingException jsonException) {
+        } catch (final JsonProcessingException jsonException) {
             log.warn("Unable to serialize exception", jsonException);
             responseBuilder.entity(e.toString()).type(MediaType.TEXT_PLAIN_TYPE);
         }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
index 86b605c..626df42 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBillingExceptionJson.java
@@ -56,7 +56,7 @@ public class TestBillingExceptionJson extends JaxrsTestSuiteNoDB {
             nil.toString();
             Assert.fail();
         } catch (final NullPointerException e) {
-            final BillingExceptionJson exceptionJson = new BillingExceptionJson(e);
+            final BillingExceptionJson exceptionJson = new BillingExceptionJson(e, true);
             Assert.assertEquals(exceptionJson.getClassName(), e.getClass().getName());
             Assert.assertNull(exceptionJson.getCode());
             Assert.assertNull(exceptionJson.getMessage());
@@ -66,6 +66,14 @@ public class TestBillingExceptionJson extends JaxrsTestSuiteNoDB {
             Assert.assertEquals(exceptionJson.getStackTrace().get(0).getClassName(), TestBillingExceptionJson.class.getName());
             Assert.assertEquals(exceptionJson.getStackTrace().get(0).getMethodName(), "testFromException");
             Assert.assertFalse(exceptionJson.getStackTrace().get(0).getNativeMethod());
+
+            final BillingExceptionJson exceptionJsonNoStackTrace = new BillingExceptionJson(e, false);
+            Assert.assertEquals(exceptionJsonNoStackTrace.getClassName(), e.getClass().getName());
+            Assert.assertNull(exceptionJsonNoStackTrace.getCode());
+            Assert.assertNull(exceptionJsonNoStackTrace.getMessage());
+            Assert.assertNull(exceptionJsonNoStackTrace.getCauseClassName());
+            Assert.assertNull(exceptionJsonNoStackTrace.getCauseMessage());
+            Assert.assertTrue(exceptionJsonNoStackTrace.getStackTrace().isEmpty());
         }
     }
 }