OutOfMemory Errors when posting large objects via RestTemplate
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,15 +18,12 @@ package org.springframework.http.converter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -44,49 +41,28 @@ import org.springframework.util.StringUtils;
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0.2
|
||||
*/
|
||||
public class ResourceHttpMessageConverter implements HttpMessageConverter<Resource> {
|
||||
public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<Resource> {
|
||||
|
||||
private static final boolean jafPresent =
|
||||
ClassUtils.isPresent("javax.activation.FileTypeMap", ResourceHttpMessageConverter.class.getClassLoader());
|
||||
|
||||
public boolean canRead(Class<?> clazz, MediaType mediaType) {
|
||||
public ResourceHttpMessageConverter() {
|
||||
super(MediaType.ALL);
|
||||
}
|
||||
@Override
|
||||
protected boolean supports(Class<?> clazz) {
|
||||
return Resource.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
||||
return Resource.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public List<MediaType> getSupportedMediaTypes() {
|
||||
return Collections.singletonList(MediaType.ALL);
|
||||
}
|
||||
|
||||
public Resource read(Class<? extends Resource> clazz, HttpInputMessage inputMessage)
|
||||
@Override
|
||||
protected Resource readInternal(Class<? extends Resource> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
|
||||
byte[] body = FileCopyUtils.copyToByteArray(inputMessage.getBody());
|
||||
return new ByteArrayResource(body);
|
||||
}
|
||||
|
||||
public void write(Resource resource, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
HttpHeaders headers = outputMessage.getHeaders();
|
||||
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
|
||||
contentType = getContentType(resource);
|
||||
}
|
||||
if (contentType != null) {
|
||||
headers.setContentType(contentType);
|
||||
}
|
||||
Long contentLength = getContentLength(resource, contentType);
|
||||
if (contentLength != null) {
|
||||
headers.setContentLength(contentLength);
|
||||
}
|
||||
FileCopyUtils.copy(resource.getInputStream(), outputMessage.getBody());
|
||||
outputMessage.getBody().flush();
|
||||
}
|
||||
|
||||
private MediaType getContentType(Resource resource) {
|
||||
@Override
|
||||
protected MediaType getDefaultContentType(Resource resource) {
|
||||
if (jafPresent) {
|
||||
return ActivationMediaTypeFactory.getMediaType(resource);
|
||||
}
|
||||
@@ -95,10 +71,22 @@ public class ResourceHttpMessageConverter implements HttpMessageConverter<Resour
|
||||
}
|
||||
}
|
||||
|
||||
protected Long getContentLength(Resource resource, MediaType contentType) throws IOException {
|
||||
return resource.contentLength();
|
||||
@Override
|
||||
protected Long getContentLength(Resource resource, MediaType contentType) {
|
||||
try {
|
||||
return resource.contentLength();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Resource resource, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
FileCopyUtils.copy(resource.getInputStream(), outputMessage.getBody());
|
||||
outputMessage.getBody().flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard-coded JAF dependency.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,25 +67,19 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
|
||||
|
||||
@Override
|
||||
protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
|
||||
Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
|
||||
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getContentLength(String s, MediaType contentType) {
|
||||
if (contentType != null && contentType.getCharSet() != null) {
|
||||
Charset charset = contentType.getCharSet();
|
||||
try {
|
||||
return (long) s.getBytes(charset.name()).length;
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
// should not occur
|
||||
throw new InternalError(ex.getMessage());
|
||||
}
|
||||
Charset charset = getContentTypeCharset(contentType);
|
||||
try {
|
||||
return (long) s.getBytes(charset.name()).length;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
// should not occur
|
||||
throw new InternalError(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +88,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
|
||||
if (writeAcceptCharset) {
|
||||
outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
|
||||
}
|
||||
MediaType contentType = outputMessage.getHeaders().getContentType();
|
||||
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
|
||||
Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
|
||||
FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
|
||||
}
|
||||
|
||||
@@ -110,4 +103,13 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
|
||||
return this.availableCharsets;
|
||||
}
|
||||
|
||||
private Charset getContentTypeCharset(MediaType contentType) {
|
||||
if (contentType != null && contentType.getCharSet() != null) {
|
||||
return contentType.getCharSet();
|
||||
}
|
||||
else {
|
||||
return DEFAULT_CHARSET;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.http.converter.xml;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerException;
|
||||
@@ -31,13 +32,14 @@ import javax.xml.transform.stream.StreamSource;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConversionException;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
|
||||
* that can read and write {@link Source} objects.
|
||||
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter} that can read and write {@link
|
||||
* Source} objects.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
@@ -84,6 +86,21 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHtt
|
||||
return new ByteArrayInputStream(bos.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getContentLength(T t, MediaType contentType) {
|
||||
if (t instanceof DOMSource) {
|
||||
try {
|
||||
CountingOutputStream os = new CountingOutputStream();
|
||||
transform(t, new StreamResult(os));
|
||||
return os.count;
|
||||
}
|
||||
catch (TransformerException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException {
|
||||
try {
|
||||
@@ -94,4 +111,24 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHtt
|
||||
}
|
||||
}
|
||||
|
||||
private static class CountingOutputStream extends OutputStream {
|
||||
|
||||
private long count = 0;
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
count++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
count += b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
count += len;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user