SmileResponseHandler implements ResponseHandler<T, RuntimeException> { @Override public T handle(Request request, Response response) { if (!successfulResponseCodes.contains(response.getStatusCode())) { throw new UnexpectedResponseException( String.format("Expected response code to be %s, but was %d: %s", successfulResponseCodes, response.getStatusCode(), response.getStatusMessage()), request, response); } String contentType = response.getHeader(CONTENT_TYPE); if (contentType == null) { throw new UnexpectedResponseException("Content-Type is not set for response", request, response); } if (!MediaType.parse(contentType).is(MEDIA_TYPE_SMILE)) { throw new UnexpectedResponseException("Expected application/x-jackson-smile response from server but got " + contentType, request, response); } try { JsonParser jsonParser = new SmileFactory().createParser(response.getInputStream()); ObjectMapper objectMapper = OBJECT_MAPPER_SUPPLIER.get(); jsonParser.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE); return objectMapper.readValue(jsonParser, objectMapper.getTypeFactory().constructType(jsonCodec.getType())); } catch (InvalidFormatException e) { throw new IllegalArgumentException("Unable to create " + jsonCodec.getType() + " from SMILE response", e); } catch (IOException e) { throw new RuntimeException("Error reading SMILE response from server", e); } } private  SmileResponseHandler(JsonCodec<T> jsonCodec); private  SmileResponseHandler(JsonCodec<T> jsonCodec, int firstSuccessfulResponseCode, int... otherSuccessfulResponseCodes); static SmileResponseHandler<T> createSmileResponseHandler(JsonCodec<T> jsonCodec); static SmileResponseHandler<T> createSmileResponseHandler(JsonCodec<T> jsonCodec, int firstSuccessfulResponseCode, int... otherSuccessfulResponseCodes); @Override T handleException(Request request, Exception exception); @Override T handle(Request request, Response response);  }
@Test public void testValidSmile() { User response = handler.handle(null, createSmileResponse(OK, ImmutableMap.of( "name", "Joe", "age", 25, "extra", true ))); assertEquals(response.getName(), "Joe"); assertEquals(response.getAge(), 25); }
@Test public void testInvalidSmile() { try { handler.handle(null, createSmileResponse(OK, ImmutableMap.of( "age", "foo" ))); } catch (IllegalArgumentException e) { assertEquals(e.getMessage(), "Unable to create " + User.class + " from SMILE response"); assertInstanceOf(e.getCause(), InvalidFormatException.class); assertContains(e.getCause().getMessage(), "Cannot deserialize value of type `int` from String \"foo\": not a valid Integer value"); } }
@Test(expectedExceptions = UnexpectedResponseException.class, expectedExceptionsMessageRegExp = "Expected application/x-jackson-smile response from server but got text/plain; charset=utf-8") public void testNonJsonResponse() { handler.handle(null, mockResponse() .contentType(PLAIN_TEXT_UTF_8) .body("hello") .build()); }
@Test(expectedExceptions = UnexpectedResponseException.class, expectedExceptionsMessageRegExp = "Content-Type is not set for response") public void testMissingContentType() { handler.handle(null, mockResponse().body("hello").build()); }
@Test(expectedExceptions = UnexpectedResponseException.class) public void testJsonErrorResponse() { String json = "{\"error\": true}"; handler.handle(null, mockResponse().status(INTERNAL_SERVER_ERROR).contentType(JSON_UTF_8).body(json).build()); }
@Test public void testJsonReadException() throws IOException { InputStream inputStream = mock(InputStream.class); IOException expectedException = new IOException("test exception"); when(inputStream.read()).thenThrow(expectedException); when(inputStream.read(any(byte[].class))).thenThrow(expectedException); when(inputStream.read(any(byte[].class), anyInt(), anyInt())).thenThrow(expectedException); try { handler.handle(null, mockResponse() .contentType(MEDIA_TYPE_SMILE) .body(inputStream) .build()); fail("expected exception"); } catch (RuntimeException e) { assertEquals(e.getMessage(), "Error reading SMILE response from server"); assertSame(e.getCause(), expectedException); } }