@Override public T extractData(ResponseEntity<HttpInputMessage> responseEntity) throws IOException { MediaType contentType = getContentType(responseEntity); for (HttpMessageConverter<?> messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter<?>) messageConverter; if (genericMessageConverter.canRead(this.responseType, null, contentType)) { return (T) genericMessageConverter.read(this.responseType, null, responseEntity.getBody()); } } if (this.responseClass != null) { if (messageConverter.canRead(this.responseClass, contentType)) { return (T) messageConverter.read((Class) this.responseClass, responseEntity.getBody()); } } } throw new WxApiResponseException("不能转换相应数据为类型:" + this.responseType, responseEntity); }
/** * Returns the media types that can be produced: * <ul> * <li>The producible media types specified in the request mappings, or * <li>Media types of configured converters that can write the specific return value, or * <li>{@link MediaType#ALL} * </ul> * @since 4.2 */ @SuppressWarnings("unchecked") protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> returnValueClass, Type returnValueType) { Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (!CollectionUtils.isEmpty(mediaTypes)) { return new ArrayList<MediaType>(mediaTypes); } else if (!this.allSupportedMediaTypes.isEmpty()) { List<MediaType> result = new ArrayList<MediaType>(); for (HttpMessageConverter<?> converter : this.messageConverters) { if (converter instanceof GenericHttpMessageConverter && returnValueType != null) { if (((GenericHttpMessageConverter<?>) converter).canWrite(returnValueType, returnValueClass, null)) { result.addAll(converter.getSupportedMediaTypes()); } } else if (converter.canWrite(returnValueClass, null)) { result.addAll(converter.getSupportedMediaTypes()); } } return result; } else { return Collections.singletonList(MediaType.ALL); } }
@Test @SuppressWarnings("unchecked") public void generics() throws IOException { GenericHttpMessageConverter<String> converter = mock(GenericHttpMessageConverter.class); List<HttpMessageConverter<?>> converters = createConverterList(converter); HttpHeaders responseHeaders = new HttpHeaders(); MediaType contentType = MediaType.TEXT_PLAIN; responseHeaders.setContentType(contentType); String expected = "Foo"; ParameterizedTypeReference<List<String>> reference = new ParameterizedTypeReference<List<String>>() {}; Type type = reference.getType(); extractor = new HttpMessageConverterExtractor<List<String>>(type, converters); given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getHeaders()).willReturn(responseHeaders); given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes())); given(converter.canRead(type, null, contentType)).willReturn(true); given(converter.read(eq(type), eq(null), any(HttpInputMessage.class))).willReturn(expected); Object result = extractor.extractData(response); assertEquals(expected, result); }
@Test @SuppressWarnings("unchecked") public void generics() throws IOException { GenericHttpMessageConverter<String> converter = mock(GenericHttpMessageConverter.class); List<HttpMessageConverter<?>> converters = createConverterList(converter); HttpHeaders responseHeaders = new HttpHeaders(); MediaType contentType = MediaType.TEXT_PLAIN; responseHeaders.setContentType(contentType); String expected = "Foo"; ParameterizedTypeReference<List<String>> reference = new ParameterizedTypeReference<List<String>>() {}; Type type = reference.getType(); extractor = new HttpMessageConverterExtractor<List<String>>(type, converters); given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getHeaders()).willReturn(responseHeaders); given(converter.canRead(type, null, contentType)).willReturn(true); given(converter.read(type, null, response)).willReturn(expected); Object result = extractor.extractData(response); assertEquals(expected, result); }
@Override public void doWithRequest(ClientHttpRequest request) throws IOException { if (responseType != null) { Class<?> responseClass = null; if (responseType instanceof Class) { responseClass = (Class<?>) responseType; } List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); for (HttpMessageConverter<?> converter : getMessageConverters()) { if (responseClass != null) { if (converter.canRead(responseClass, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } else if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter; if (genericConverter.canRead(responseType, null, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } } if (!allSupportedMediaTypes.isEmpty()) { MediaType.sortBySpecificity(allSupportedMediaTypes); if (logger.isDebugEnabled()) { logger.debug("Setting request Accept header to " + allSupportedMediaTypes); } request.getHeaders().setAccept(allSupportedMediaTypes); } } }
@Override @SuppressWarnings({ "unchecked", "rawtypes" }) public T extractData(ClientHttpResponse response) throws IOException { if (!hasMessageBody(response)) { return null; } MediaType contentType = getContentType(response); for (HttpMessageConverter<?> messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter<?>) messageConverter; if (genericMessageConverter.canRead(this.responseType, null, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseType + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) genericMessageConverter.read(this.responseType, null, response); } } if (this.responseClass != null) { if (messageConverter.canRead(this.responseClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseClass.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) messageConverter.read((Class) this.responseClass, response); } } } throw new RestClientException( "Could not extract response: no suitable HttpMessageConverter found for response type [" + this.responseType + "] and content type [" + contentType + "]"); }
@Override public void doWithRequest(ClientHttpRequest request) throws IOException { if (this.responseType != null) { Class<?> responseClass = null; if (this.responseType instanceof Class) { responseClass = (Class<?>) this.responseType; } List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); for (HttpMessageConverter<?> converter : getMessageConverters()) { if (responseClass != null) { if (converter.canRead(responseClass, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } else if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter; if (genericConverter.canRead(this.responseType, null, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } } if (!allSupportedMediaTypes.isEmpty()) { MediaType.sortBySpecificity(allSupportedMediaTypes); if (logger.isDebugEnabled()) { logger.debug("Setting request Accept header to " + allSupportedMediaTypes); } request.getHeaders().setAccept(allSupportedMediaTypes); } } }
@Override @SuppressWarnings({"unchecked", "rawtypes"}) public T extractData(ClientHttpResponse response) throws IOException { MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response); if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) { return null; } MediaType contentType = getContentType(responseWrapper); for (HttpMessageConverter<?> messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter<?>) messageConverter; if (genericMessageConverter.canRead(this.responseType, null, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseType + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) genericMessageConverter.read(this.responseType, null, responseWrapper); } } if (this.responseClass != null) { if (messageConverter.canRead(this.responseClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseClass.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) messageConverter.read((Class) this.responseClass, responseWrapper); } } } throw new RestClientException("Could not extract response: no suitable HttpMessageConverter found " + "for response type [" + this.responseType + "] and content type [" + contentType + "]"); }
@SuppressWarnings("unchecked") @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (type instanceof Class || type instanceof ParameterizedType) { //MediaType contentType = getContentType(responseWrapper); MediaType contentType = MediaType.APPLICATION_JSON; //TODO: determine dynamically? Class<?> responseClass = (type instanceof Class) ? (Class<?>) type : null; for (HttpMessageConverter<?> messageConverter : this.messageConverters.getObject().getConverters()) { if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter<?>) messageConverter; if (genericMessageConverter.canRead(type, null, contentType)) { if (log.isDebugEnabled()) { log.debug("Reading [" + type + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return new SpringResponseConverter(genericMessageConverter, type); } } if (responseClass != null) { if (messageConverter.canRead(responseClass, contentType)) { if (log.isDebugEnabled()) { log.debug("Reading [" + responseClass.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return new SpringResponseConverter(messageConverter, responseClass); } } } } return null; }
@SuppressWarnings("unchecked") public void doWithRequest(ClientHttpRequest request) throws IOException { if (responseType != null) { Class<?> responseClass = null; if (responseType instanceof Class) { responseClass = (Class<?>) responseType; } List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); for (HttpMessageConverter<?> converter : getMessageConverters()) { if (responseClass != null) { if (converter.canRead(responseClass, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } else if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter; if (genericConverter.canRead(responseType, null, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } } } if (!allSupportedMediaTypes.isEmpty()) { MediaType.sortBySpecificity(allSupportedMediaTypes); if (logger.isDebugEnabled()) { logger.debug("Setting request Accept header to " + allSupportedMediaTypes); } request.getHeaders().setAccept(allSupportedMediaTypes); } } }
@SuppressWarnings("unchecked") public T extractData(ClientHttpResponse response) throws IOException { if (!hasMessageBody(response)) { return null; } MediaType contentType = getContentType(response); for (HttpMessageConverter messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter genericMessageConverter = (GenericHttpMessageConverter) messageConverter; if (genericMessageConverter.canRead(this.responseType, null, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseType + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) genericMessageConverter.read(this.responseType, null, response); } } if (this.responseClass != null) { if (messageConverter.canRead(this.responseClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + this.responseClass.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]"); } return (T) messageConverter.read(this.responseClass, response); } } } throw new RestClientException( "Could not extract response: no suitable HttpMessageConverter found for response type [" + this.responseType + "] and content type [" + contentType + "]"); }
@Test @SuppressWarnings("rawtypes") public void exchangeParameterizedType() throws Exception { GenericHttpMessageConverter converter = mock(GenericHttpMessageConverter.class); template.setMessageConverters(Collections.<HttpMessageConverter<?>>singletonList(converter)); ParameterizedTypeReference<List<Integer>> intList = new ParameterizedTypeReference<List<Integer>>() {}; given(converter.canRead(intList.getType(), null, null)).willReturn(true); given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); given(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).willReturn(this.request); HttpHeaders requestHeaders = new HttpHeaders(); given(this.request.getHeaders()).willReturn(requestHeaders); given(converter.canWrite(String.class, null)).willReturn(true); String requestBody = "Hello World"; converter.write(requestBody, null, this.request); given(this.request.execute()).willReturn(response); given(errorHandler.hasError(response)).willReturn(false); List<Integer> expected = Collections.singletonList(42); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getHeaders()).willReturn(responseHeaders); given(response.getBody()).willReturn(new ByteArrayInputStream(new Integer(42).toString().getBytes())); given(converter.canRead(intList.getType(), null, MediaType.TEXT_PLAIN)).willReturn(true); given(converter.read(eq(intList.getType()), eq(null), any(HttpInputMessage.class))).willReturn(expected); given(response.getStatusCode()).willReturn(HttpStatus.OK); HttpStatus status = HttpStatus.OK; given(response.getStatusCode()).willReturn(status); given(response.getStatusText()).willReturn(status.getReasonPhrase()); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.set("MyHeader", "MyValue"); HttpEntity<String> requestEntity = new HttpEntity<String>(requestBody, entityHeaders); ResponseEntity<List<Integer>> result = template.exchange("http://example.com", HttpMethod.POST, requestEntity, intList); assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); assertEquals("Invalid custom header", "MyValue", requestHeaders.getFirst("MyHeader")); assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode()); verify(response).close(); }
public SpringResponseConverter(GenericHttpMessageConverter<?> genericMessageConverter, Type type) { this.genericMessageConverter = genericMessageConverter; this.type = type; }
/** * Creates the method argument value of the expected parameter type by reading * from the given HttpInputMessage. * * @param <T> the expected type of the argument value to be created * @param inputMessage the HTTP input message representing the current request * @param methodParam the method argument * @param targetType the type of object to create, not necessarily the same as * the method parameter type (e.g. for {@code HttpEntity<String>} method * parameter the target type is String) * @return the created method argument value * @throws IOException if the reading from the request fails * @throws HttpMediaTypeNotSupportedException if no suitable message converter is found */ @SuppressWarnings("unchecked") protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException { MediaType contentType; try { contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { contentType = MediaType.APPLICATION_OCTET_STREAM; } Class<?> contextClass = methodParam.getDeclaringClass(); Map<TypeVariable, Type> map = GenericTypeResolver.getTypeVariableMap(contextClass); Class<T> targetClass = (Class<T>) GenericTypeResolver.resolveType(targetType, map); for (HttpMessageConverter<?> converter : this.messageConverters) { if (converter instanceof GenericHttpMessageConverter) { GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; if (genericConverter.canRead(targetType, contextClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + targetType + "] as \"" + contentType + "\" using [" + converter + "]"); } return genericConverter.read(targetType, contextClass, inputMessage); } } if (targetClass != null) { if (converter.canRead(targetClass, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + targetClass.getName() + "] as \"" + contentType + "\" using [" + converter + "]"); } return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage); } } } throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); }
@Test public void exchangeParameterizedType() throws Exception { GenericHttpMessageConverter converter = mock(GenericHttpMessageConverter.class); template.setMessageConverters(Collections.<HttpMessageConverter<?>>singletonList(converter)); ParameterizedTypeReference<List<Integer>> intList = new ParameterizedTypeReference<List<Integer>>() {}; given(converter.canRead(intList.getType(), null, null)).willReturn(true); given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); given(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).willReturn(this.request); HttpHeaders requestHeaders = new HttpHeaders(); given(this.request.getHeaders()).willReturn(requestHeaders); given(converter.canWrite(String.class, null)).willReturn(true); String requestBody = "Hello World"; converter.write(requestBody, null, this.request); given(this.request.execute()).willReturn(response); given(errorHandler.hasError(response)).willReturn(false); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getHeaders()).willReturn(responseHeaders); List<Integer> expected = Collections.singletonList(42); given(converter.canRead(intList.getType(), null, MediaType.TEXT_PLAIN)).willReturn(true); given(converter.read(intList.getType(), null, response)).willReturn(expected); given(response.getStatusCode()).willReturn(HttpStatus.OK); HttpStatus status = HttpStatus.OK; given(response.getStatusCode()).willReturn(status); given(response.getStatusText()).willReturn(status.getReasonPhrase()); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.set("MyHeader", "MyValue"); HttpEntity<String> requestEntity = new HttpEntity<String>(requestBody, entityHeaders); ResponseEntity<List<Integer>> result = template.exchange("http://example.com", HttpMethod.POST, requestEntity, intList); assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); assertEquals("Invalid custom header", "MyValue", requestHeaders.getFirst("MyHeader")); assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode()); verify(response).close(); }