diff --git a/src/main/java/com/gocardless/errors/MalformedResponseException.java b/src/main/java/com/gocardless/errors/MalformedResponseException.java index 2962de41..e438cf34 100644 --- a/src/main/java/com/gocardless/errors/MalformedResponseException.java +++ b/src/main/java/com/gocardless/errors/MalformedResponseException.java @@ -7,14 +7,43 @@ * HTML error page returned from a load balancer) */ public class MalformedResponseException extends GoCardlessException { + private static final int UNKNOWN_STATUS_CODE = -1; + private static final int BODY_PREVIEW_MAX_LENGTH = 500; + private final int statusCode; private final String responseBody; public MalformedResponseException(String responseBody) { - super("Malformed response received from server"); + this(UNKNOWN_STATUS_CODE, responseBody); + } + + public MalformedResponseException(int statusCode, String responseBody) { + super(buildMessage(statusCode, responseBody)); + this.statusCode = statusCode; this.responseBody = responseBody; } + /** + * @return the HTTP status code of the malformed response, or -1 if unknown. + */ + public int getStatusCode() { + return statusCode; + } + public String getResponseBody() { return responseBody; } + + private static String buildMessage(int statusCode, String responseBody) { + StringBuilder message = new StringBuilder("Malformed response received from server"); + if (statusCode != UNKNOWN_STATUS_CODE) { + message.append(" (HTTP ").append(statusCode).append(")"); + } + if (responseBody != null && !responseBody.isEmpty()) { + String preview = responseBody.length() > BODY_PREVIEW_MAX_LENGTH + ? responseBody.substring(0, BODY_PREVIEW_MAX_LENGTH) + "..." + : responseBody; + message.append(": ").append(preview); + } + return message.toString(); + } } diff --git a/src/main/java/com/gocardless/http/ResponseParser.java b/src/main/java/com/gocardless/http/ResponseParser.java index 494af8f3..6282edac 100644 --- a/src/main/java/com/gocardless/http/ResponseParser.java +++ b/src/main/java/com/gocardless/http/ResponseParser.java @@ -56,15 +56,22 @@ GoCardlessApiException parseError(String responseBody, int statusCode) { try { json = new JsonParser().parse(responseBody); } catch (JsonSyntaxException e) { - throw new MalformedResponseException(responseBody); + throw new MalformedResponseException(statusCode, responseBody); } - JsonElement errorElement = json.getAsJsonObject().get("error"); - if (errorElement.isJsonPrimitive()) { - ApiErrorResponse error = - ApiErrorResponse.fromMessage(errorElement.getAsString(), statusCode); + try { + JsonElement errorElement = json.getAsJsonObject().get("error"); + if (errorElement == null || errorElement.isJsonNull()) { + throw new MalformedResponseException(statusCode, responseBody); + } + if (errorElement.isJsonPrimitive()) { + ApiErrorResponse error = + ApiErrorResponse.fromMessage(errorElement.getAsString(), statusCode); + return GoCardlessErrorMapper.toException(error); + } + ApiErrorResponse error = gson.fromJson(errorElement, ApiErrorResponse.class); return GoCardlessErrorMapper.toException(error); + } catch (IllegalStateException | ClassCastException | JsonSyntaxException e) { + throw new MalformedResponseException(statusCode, responseBody); } - ApiErrorResponse error = gson.fromJson(errorElement, ApiErrorResponse.class); - return GoCardlessErrorMapper.toException(error); } } diff --git a/src/test/java/com/gocardless/http/ResponseParserTest.java b/src/test/java/com/gocardless/http/ResponseParserTest.java index f2bd1dee..78efe7fd 100644 --- a/src/test/java/com/gocardless/http/ResponseParserTest.java +++ b/src/test/java/com/gocardless/http/ResponseParserTest.java @@ -3,6 +3,7 @@ import static com.gocardless.errors.ErrorType.*; import static com.google.common.base.Charsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; import com.gocardless.errors.*; import com.gocardless.http.HttpTestUtil.DummyItem; @@ -166,6 +167,20 @@ public void shouldHandleNonJsonResponse() throws IOException { parser.parseError(responseBody, 500); } + @Test + public void shouldIncludeStatusCodeAndBodyForNonJsonErrorResponse() throws IOException { + URL resource = Resources.getResource("fixtures/non_json_response.html"); + String responseBody = Resources.toString(resource, UTF_8); + try { + parser.parseError(responseBody, 502); + fail("expected MalformedResponseException"); + } catch (MalformedResponseException e) { + assertThat(e.getStatusCode()).isEqualTo(502); + assertThat(e.getResponseBody()).isEqualTo(responseBody); + assertThat(e.getMessage()).contains("HTTP 502"); + } + } + @Test public void shouldHandleAuthenticationError() throws IOException { URL resource = Resources.getResource("fixtures/unauthorized_error.json");