diff --git a/src/main/java/com/tumblr/jumblr/exceptions/JumblrException.java b/src/main/java/com/tumblr/jumblr/exceptions/JumblrException.java index 5eb2f4d..c535e3e 100644 --- a/src/main/java/com/tumblr/jumblr/exceptions/JumblrException.java +++ b/src/main/java/com/tumblr/jumblr/exceptions/JumblrException.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import com.tumblr.jumblr.types.JumblrError; import org.scribe.model.Response; @@ -17,7 +18,7 @@ public class JumblrException extends RuntimeException { private final int responseCode; private String message; - private List errors; + private List errors; /** * Instantiate a new JumblrException given a bad response to wrap @@ -63,7 +64,7 @@ public String getMessage() { * Get the errors returned from the API * @return the errors (or null if none) */ - public List getErrors() { + public List getErrors() { return this.errors; } @@ -72,21 +73,29 @@ public List getErrors() { * @param object the parsed response object */ private void extractErrors(JsonObject object) { - JsonObject response; + JsonArray responseErrors; try { - response = object.getAsJsonObject("response"); + responseErrors = object.getAsJsonArray("errors"); } catch (ClassCastException ex) { - return; // response is non-object + return; // errors is non-array } - if (response == null) { return; } - - JsonArray e = response.getAsJsonArray("errors"); - if (e == null) { return; } + if (responseErrors == null) { return; } // Set the errors - errors = new ArrayList(e.size()); - for (int i = 0; i < e.size(); i++) { - errors.add(e.get(i).getAsString()); + errors = new ArrayList(responseErrors.size()); + for (int i = 0; i < responseErrors.size(); i++) { + JsonElement errorElement = responseErrors.get(i); + JumblrError error = new JumblrError(); + if (errorElement.isJsonObject()) { + JsonObject errorJson = errorElement.getAsJsonObject(); + error.setTitle(errorJson.get("title").getAsString()); + error.setCode(errorJson.get("code").getAsInt()); + error.setDetail(errorJson.get("detail").getAsString()); + } + else { + error.setDetail(errorElement.getAsString()); + } + errors.add(error); } } @@ -113,7 +122,7 @@ private void extractMessage(JsonObject object) { } // Otherwise set a default - this.message = "Unknown Error"; + this.message = "Unknown JumblrError"; } } diff --git a/src/main/java/com/tumblr/jumblr/types/JumblrError.java b/src/main/java/com/tumblr/jumblr/types/JumblrError.java new file mode 100644 index 0000000..9da88d3 --- /dev/null +++ b/src/main/java/com/tumblr/jumblr/types/JumblrError.java @@ -0,0 +1,66 @@ +package com.tumblr.jumblr.types; + +/** + * This class represents an error that comes back from an API response. + * + * Example response with an error: + * + * { + * "meta": { + * "status": 404, + * "msg": "Not Found" + * }, + * "response": [], + * "errors": [ + * { + * "title": "Not Found", + * "code": 4012, + * "detail": "This Tumblr is only viewable within the Tumblr dashboard" + * } + * ] + * } + * + * @author ndtreviv + */ +public class JumblrError { + + private String title; + private Integer code; + private String detail; + + /** + * Get the error title + * @return error title + */ + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + /** + * Get the error code + * @return error code + */ + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + /** + * Get the error detail + * @return error detail + */ + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } +} diff --git a/src/test/java/com/tumblr/jumblr/exceptions/JumblrExceptionTest.java b/src/test/java/com/tumblr/jumblr/exceptions/JumblrExceptionTest.java new file mode 100644 index 0000000..fcc148e --- /dev/null +++ b/src/test/java/com/tumblr/jumblr/exceptions/JumblrExceptionTest.java @@ -0,0 +1,105 @@ +package com.tumblr.jumblr.exceptions; + +import com.tumblr.jumblr.types.JumblrError; +import org.junit.Test; +import org.scribe.model.Response; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests for JumblrException + */ +public class JumblrExceptionTest { + + @Test + public void extractsMultiTypeErrors() { + // given + String content = "{\n" + + " \"meta\": {\n" + + " \"status\": 404,\n" + + " \"msg\": \"Not Found\"\n" + + " },\n" + + " \"response\": [],\n" + + " \"errors\": [\n" + + " \"test\"," + + " {\n" + + " \"title\": \"Not Found\",\n" + + " \"code\": 4012,\n" + + " \"detail\": \"This Tumblr is only viewable within the Tumblr dashboard\"\n" + + " }\n" + + " ]\n" + + "}"; + + Response response = mock(Response.class); + when(response.getCode()).thenReturn(404); + when(response.getBody()).thenReturn(content); + + // when + JumblrException exception = new JumblrException(response); + + // then + List errors = exception.getErrors(); + assertNotNull(errors); + assertEquals("Found two errors", errors.size(), 2); + assertEquals("Found string error", "test", errors.get(0).getDetail()); + assertEquals("Found object error title", "Not Found", errors.get(1).getTitle()); + assertEquals("Found object error code", new Integer(4012), errors.get(1).getCode()); + assertEquals("Found object error detail", "This Tumblr is only viewable within the Tumblr dashboard", errors.get(1).getDetail()); + } + + @Test + public void extractsErrorsWithEmptyArray() { + // given + String content = "{\n" + + " \"meta\": {\n" + + " \"status\": 404,\n" + + " \"msg\": \"Not Found\"\n" + + " },\n" + + " \"response\": [],\n" + + " \"errors\": []\n" + + "}"; + + Response response = mock(Response.class); + when(response.getCode()).thenReturn(200); + when(response.getBody()).thenReturn(content); + + // when + JumblrException exception = new JumblrException(response); + + // then + List errors = exception.getErrors(); + assertNotNull(errors); + assertEquals("Found no errors", errors.size(), 0); + } + + @Test + public void errorExtractionDoesNotFailWithNull() { + // given + String content = "{\n" + + " \"meta\": {\n" + + " \"status\": 404,\n" + + " \"msg\": \"Not Found\"\n" + + " },\n" + + " \"response\": []" + + "}"; + + Response response = mock(Response.class); + when(response.getCode()).thenReturn(200); + when(response.getBody()).thenReturn(content); + + // when + JumblrException exception = new JumblrException(response); + + // then + List errors = exception.getErrors(); + assertNull(errors); + } + +} +