OutOfMemory Errors when posting large objects via RestTemplate
This commit is contained in:
parent
2ed3d77331
commit
33674933ea
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.http.converter.xml;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.Source;
|
||||
|
|
@ -24,7 +25,6 @@ import javax.xml.transform.dom.DOMSource;
|
|||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import static org.custommonkey.xmlunit.XMLAssert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
|
@ -36,6 +36,8 @@ import org.springframework.http.MockHttpInputMessage;
|
|||
import org.springframework.http.MockHttpOutputMessage;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.custommonkey.xmlunit.XMLAssert.*;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
@SuppressWarnings("unchecked")
|
||||
public class SourceHttpMessageConverterTests {
|
||||
|
|
@ -100,7 +102,7 @@ public class SourceHttpMessageConverterTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void write() throws Exception {
|
||||
public void writeDOMSource() throws Exception {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
documentBuilderFactory.setNamespaceAware(true);
|
||||
Document document = documentBuilderFactory.newDocumentBuilder().newDocument();
|
||||
|
|
@ -115,7 +117,34 @@ public class SourceHttpMessageConverterTests {
|
|||
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
assertEquals("Invalid content-type", new MediaType("application", "xml"),
|
||||
outputMessage.getHeaders().getContentType());
|
||||
assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
|
||||
outputMessage.getHeaders().getContentLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeSAXSource() throws Exception {
|
||||
String xml = "<root>Hello World</root>";
|
||||
SAXSource saxSource = new SAXSource(new InputSource(new StringReader(xml)));
|
||||
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
converter.write(saxSource, null, outputMessage);
|
||||
assertXMLEqual("Invalid result", "<root>Hello World</root>",
|
||||
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
assertEquals("Invalid content-type", new MediaType("application", "xml"),
|
||||
outputMessage.getHeaders().getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeStreamSource() throws Exception {
|
||||
String xml = "<root>Hello World</root>";
|
||||
StreamSource streamSource = new StreamSource(new StringReader(xml));
|
||||
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
converter.write(streamSource, null, outputMessage);
|
||||
assertXMLEqual("Invalid result", "<root>Hello World</root>",
|
||||
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
assertEquals("Invalid content-type", new MediaType("application", "xml"),
|
||||
outputMessage.getHeaders().getContentType());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue