From 2de9e2a38db4338fd70af69d50e6153397755196 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Sat, 21 Feb 2009 13:34:55 +0000 Subject: [PATCH] Added HTTP conversion abstraction for RestTemplate --- .../AbstractHttpMessageConverter.java | 144 ++++++++++++++++++ .../ByteArrayHttpMessageConverter.java | 79 ++++++++++ .../HttpMessageConversionException.java | 47 ++++++ .../web/converter/HttpMessageConverter.java | 70 +++++++++ .../converter/StringHttpMessageConverter.java | 99 ++++++++++++ .../web/converter/package.html | 7 + .../springframework/web/http/HttpHeaders.java | 53 ++++++- .../ByteArrayHttpMessageConverterTests.java | 61 ++++++++ .../StringHttpMessageConverterTests.java | 66 ++++++++ .../web/http/HttpHeadersTests.java | 14 +- 10 files changed, 636 insertions(+), 4 deletions(-) create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/AbstractHttpMessageConverter.java create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/ByteArrayHttpMessageConverter.java create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConversionException.java create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConverter.java create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/StringHttpMessageConverter.java create mode 100644 org.springframework.web/src/main/java/org/springframework/web/converter/package.html create mode 100644 org.springframework.web/src/test/java/org/springframework/web/converter/ByteArrayHttpMessageConverterTests.java create mode 100644 org.springframework.web/src/test/java/org/springframework/web/converter/StringHttpMessageConverterTests.java diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/AbstractHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/web/converter/AbstractHttpMessageConverter.java new file mode 100644 index 00000000000..b9a08d3284c --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/AbstractHttpMessageConverter.java @@ -0,0 +1,144 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; +import org.springframework.util.MediaType; +import org.springframework.web.http.HttpHeaders; +import org.springframework.web.http.HttpOutputMessage; + +/** + * Abstract base class for most {@link HttpMessageConverter} implementations. + * + *

This base class adds support for setting supported {@code MediaTypes}, through the {@link + * #setSupportedMediaTypes(List) supportedMediaTypes} bean property. It also adds support for {@code Content-Type} and + * {@code Content-Length} when writing to output messages. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public abstract class AbstractHttpMessageConverter implements HttpMessageConverter { + + /** + * Logger available to subclasses. + */ + protected final Log logger = LogFactory.getLog(getClass()); + + private List supportedMediaTypes = Collections.emptyList(); + + /** + * Constructs an {@code AbstractHttpMessageConverter} with no supported media types. + * + * @see #setSupportedMediaTypes(List) + */ + protected AbstractHttpMessageConverter() { + } + + /** + * Constructs an {@code AbstractHttpMessageConverter} with one supported media type. + */ + protected AbstractHttpMessageConverter(MediaType supportedMediaType) { + setSupportedMediaTypes(Collections.singletonList(supportedMediaType)); + } + + /** + * Constructs an {@code AbstractHttpMessageConverter} with multiple supported media type. + */ + protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) { + setSupportedMediaTypes(Arrays.asList(supportedMediaTypes)); + } + + public List getSupportedMediaTypes() { + return Collections.unmodifiableList(supportedMediaTypes); + } + + /** + * Sets the list of {@link MediaType} objects supported by this converter. + */ + public void setSupportedMediaTypes(List supportedMediaTypes) { + Assert.notEmpty(supportedMediaTypes, "'supportedMediaTypes' must not be empty"); + this.supportedMediaTypes = new ArrayList(supportedMediaTypes); + } + + /** + * {@inheritDoc} + * + *

This implementation delegates to {@link #getContentType(Object)} and {@link #getContentLength(Object)}, and sets + * the corresponding headers on the output message. It then calls {@link #writeToInternal(Object, HttpOutputMessage)}. + * + * @throws HttpMessageConversionException in case of conversion errors + */ + public final void write(T t, HttpOutputMessage outputMessage) throws IOException { + HttpHeaders headers = outputMessage.getHeaders(); + MediaType contentType = getContentType(t); + if (contentType != null) { + headers.setContentType(contentType); + } + Long contentLength = getContentLength(t); + if (contentLength != null) { + headers.setContentLength(contentLength); + } + writeToInternal(t, outputMessage); + outputMessage.getBody().flush(); + } + + /** + * Returns the content type for the given type. + * + *

By default, this returns the first element of the {@link #setSupportedMediaTypes(List) supportedMediaTypes} + * property, if any. Can be overriden in subclasses. + * + * @param t the type to return the content type for + * @return the content type, or null if not known + */ + protected MediaType getContentType(T t) { + List mediaTypes = getSupportedMediaTypes(); + return !mediaTypes.isEmpty() ? mediaTypes.get(0) : null; + } + + /** + * Returns the content length for the given type. + * + *

By default, this returns null. Can be overriden in subclasses. + * + * @param t the type to return the content length for + * @return the content length, or null if not known + */ + protected Long getContentLength(T t) { + return null; + } + + /** + * Abstract template method that writes the actualy body. Invoked from {@link #write(Object, HttpOutputMessage)}. + * + * @param t the object to write to the output message + * @param outputMessage the message to write to + * @throws IOException in case of I/O errors + * @throws HttpMessageConversionException in case of conversion errors + */ + protected abstract void writeToInternal(T t, HttpOutputMessage outputMessage) throws IOException; + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/ByteArrayHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/web/converter/ByteArrayHttpMessageConverter.java new file mode 100644 index 00000000000..c64455a7bc3 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/ByteArrayHttpMessageConverter.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.springframework.util.FileCopyUtils; +import org.springframework.util.MediaType; +import org.springframework.web.http.HttpInputMessage; +import org.springframework.web.http.HttpOutputMessage; + +/** + * Implementation of {@link HttpMessageConverter} that can read and write byte arrays. + * + *

By default, this converter supports all media types (*/*), and writes with a {@code + * Content-Type} of {@code application/octet-stream}. This can be overridden by setting the {@link + * #setSupportedMediaTypes(java.util.List) supportedMediaTypes} property, and overridding {@link + * #getContentType(byte[])}. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter { + + /** + * Creates a new instance of the {@code ByteArrayHttpMessageConverter}. + */ + public ByteArrayHttpMessageConverter() { + super(MediaType.ALL); + } + + public boolean supports(Class clazz) { + return byte[].class == clazz; + } + + public byte[] read(Class clazz, HttpInputMessage inputMessage) throws IOException { + long contentLength = inputMessage.getHeaders().getContentLength(); + if (contentLength >= 0) { + ByteArrayOutputStream bos = new ByteArrayOutputStream((int) contentLength); + FileCopyUtils.copy(inputMessage.getBody(), bos); + return bos.toByteArray(); + } + else { + return FileCopyUtils.copyToByteArray(inputMessage.getBody()); + } + } + + @Override + protected MediaType getContentType(byte[] bytes) { + return new MediaType("application", "octet-stream"); + } + + @Override + protected Long getContentLength(byte[] bytes) { + return (long) bytes.length; + } + + @Override + protected void writeToInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException { + FileCopyUtils.copy(bytes, outputMessage.getBody()); + } + + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConversionException.java b/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConversionException.java new file mode 100644 index 00000000000..f3bba114031 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConversionException.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import org.springframework.core.NestedRuntimeException; + +/** + * Thrown by {@link HttpMessageConverter} implementations when the conversion fails. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class HttpMessageConversionException extends NestedRuntimeException { + + /** + * Create a new MessageConversionException. + * + * @param msg the detail message + */ + public HttpMessageConversionException(String msg) { + super(msg); + } + + /** + * Create a new MessageConversionException. + * + * @param msg the detail message + * @param cause the root cause (if any) + */ + public HttpMessageConversionException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConverter.java new file mode 100644 index 00000000000..bbca0e7083b --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/HttpMessageConverter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.IOException; +import java.util.List; + +import org.springframework.util.MediaType; +import org.springframework.web.http.HttpInputMessage; +import org.springframework.web.http.HttpOutputMessage; + +/** + * Strategy interface that specifies a converter can convert from and to HTTP request and responses. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public interface HttpMessageConverter { + + /** + * Indicates whether the given class is supported by this converter. + * + *

Typically implemented using an {@code instanceof} check. + * + * @param clazz the class to test for support + * @return true if supported; false otherwise + */ + boolean supports(Class clazz); + + /** + * Returns the list of {@link MediaType} objects supported by this converter. + */ + List getSupportedMediaTypes(); + + /** + * Reads an object of the given type form the given input message, and returns it. + * + * @param clazz the type of object to return + * @param inputMessage the HTTP input message to read from + * @return the converted object + * @throws IOException in case of I/O errors + * @throws HttpMessageConversionException in case of conversion errors + */ + T read(Class clazz, HttpInputMessage inputMessage) throws IOException; + + /** + * Writes an given object to the given output message. + * + * @param t the object to write to the output message + * @param outputMessage the message to write to + * @throws IOException in case of I/O errors + * @throws HttpMessageConversionException in case of conversion errors + */ + void write(T t, HttpOutputMessage outputMessage) throws IOException; + +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/StringHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/web/converter/StringHttpMessageConverter.java new file mode 100644 index 00000000000..a77781dc37c --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/StringHttpMessageConverter.java @@ -0,0 +1,99 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.util.FileCopyUtils; +import org.springframework.util.MediaType; +import org.springframework.web.http.HttpInputMessage; +import org.springframework.web.http.HttpOutputMessage; + +/** + * Implementation of {@link HttpMessageConverter} that can read and write strings. + * + *

By default, this converter supports all text media types (text/*), and writes with a {@code + * Content-Type} of {@code text/plain}. This can be overridden by setting the {@link + * #setSupportedMediaTypes(java.util.List) supportedMediaTypes} property. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class StringHttpMessageConverter extends AbstractHttpMessageConverter { + + public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); + + private final List availableCharsets; + + public StringHttpMessageConverter() { + super(new MediaType("text", "plain", DEFAULT_CHARSET), new MediaType("text", "*")); + availableCharsets = new ArrayList(Charset.availableCharsets().values()); + } + + public boolean supports(Class clazz) { + return String.class.equals(clazz); + } + + public String read(Class clazz, HttpInputMessage inputMessage) throws IOException { + MediaType contentType = inputMessage.getHeaders().getContentType(); + Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; + return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset)); + } + + @Override + protected Long getContentLength(String s) { + Charset charset = getContentType(s).getCharSet(); + if (charset != null) { + try { + return (long) s.getBytes(charset.name()).length; + } + catch (UnsupportedEncodingException ex) { + // should not occur + throw new InternalError(ex.getMessage()); + } + } + else { + return null; + } + } + + @Override + protected void writeToInternal(String s, HttpOutputMessage outputMessage) throws IOException { + outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets()); + MediaType contentType = getContentType(s); + Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; + FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset)); + } + + /** + * Returns the list of supported {@link Charset}. + * + *

By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses. + * + * @return the list of accepted charsets + */ + protected List getAcceptedCharsets() { + return availableCharsets; + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/converter/package.html b/org.springframework.web/src/main/java/org/springframework/web/converter/package.html new file mode 100644 index 00000000000..51673583dca --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/converter/package.html @@ -0,0 +1,7 @@ + + + +Provides a HttpMessageConverter abstraction to convert between Java objects and HTTP input/output messages. + + + diff --git a/org.springframework.web/src/main/java/org/springframework/web/http/HttpHeaders.java b/org.springframework.web/src/main/java/org/springframework/web/http/HttpHeaders.java index f33828a6ab6..8b174c31304 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/http/HttpHeaders.java +++ b/org.springframework.web/src/main/java/org/springframework/web/http/HttpHeaders.java @@ -17,12 +17,15 @@ package org.springframework.web.http; import java.net.URI; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -48,6 +51,8 @@ public final class HttpHeaders implements Map> { private static String ACCEPT = "Accept"; + private static String ACCEPT_CHARSET = "Accept-Charset"; + private static String ALLOW = "Allow"; private static String CONTENT_LENGTH = "Content-Length"; @@ -59,8 +64,9 @@ public final class HttpHeaders implements Map> { private Map> headers = CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(5); /** - * Returns the list of acceptable {@link MediaType media types}, as specified by the Accept header.

- * Returns an empty list when the acceptable media types are unspecified. + * Returns the list of acceptable {@linkplain MediaType media types}, as specified by the Accept header. + * + *

Returns an empty list when the acceptable media types are unspecified. * * @return the acceptable media types */ @@ -70,7 +76,7 @@ public final class HttpHeaders implements Map> { } /** - * Sets the list of acceptable {@link MediaType media types}, as specified by the Accept header. + * Sets the list of acceptable {@linkplain MediaType media types}, as specified by the Accept header. * * @param acceptableMediaTypes the acceptable media types */ @@ -78,6 +84,47 @@ public final class HttpHeaders implements Map> { set(ACCEPT, MediaType.toString(acceptableMediaTypes)); } + /** + * Returns the list of acceptable {@linkplain Charset charsets}, as specified by the Accept-Charset + * header. + * + * @return the acceptable charsets + */ + public List getAcceptCharset() { + List result = new ArrayList(); + String value = getFirst(ACCEPT_CHARSET); + if (value != null) { + String[] tokens = value.split(",\\s*"); + for (String token : tokens) { + int paramIdx = token.indexOf(';'); + if (paramIdx == -1) { + result.add(Charset.forName(token)); + } + else { + result.add(Charset.forName(token.substring(0, paramIdx))); + } + } + } + return result; + } + + /** + * Sets the list of acceptable {@linkplain Charset charsets}, as specified by the Accept-Charset header. + * + * @param acceptableCharsets the acceptable charsets + */ + public void setAcceptCharset(List acceptableCharsets) { + StringBuilder builder = new StringBuilder(); + for (Iterator iterator = acceptableCharsets.iterator(); iterator.hasNext();) { + Charset charset = iterator.next(); + builder.append(charset.name().toLowerCase(Locale.ENGLISH)); + if (iterator.hasNext()) { + builder.append(", "); + } + } + set(ACCEPT_CHARSET, builder.toString()); + } + /** * Returns the set of allowed {@link HttpMethod HTTP methods}, as specified by the Allow header.

* Returns an empty set when the allowed methods are unspecified. diff --git a/org.springframework.web/src/test/java/org/springframework/web/converter/ByteArrayHttpMessageConverterTests.java b/org.springframework.web/src/test/java/org/springframework/web/converter/ByteArrayHttpMessageConverterTests.java new file mode 100644 index 00000000000..274a45f237e --- /dev/null +++ b/org.springframework.web/src/test/java/org/springframework/web/converter/ByteArrayHttpMessageConverterTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.IOException; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.util.MediaType; +import org.springframework.web.http.MockHttpInputMessage; +import org.springframework.web.http.MockHttpOutputMessage; + +/** + * @author Arjen Poutsma + */ +public class ByteArrayHttpMessageConverterTests { + + private ByteArrayHttpMessageConverter converter; + + @Before + public void setUp() { + converter = new ByteArrayHttpMessageConverter(); + } + + @Test + public void read() throws IOException { + byte[] body = new byte[]{0x1, 0x2}; + MockHttpInputMessage inputMessage = new MockHttpInputMessage(body); + inputMessage.getHeaders().setContentType(new MediaType("application", "octet-stream")); + byte[] result = converter.read(byte[].class, inputMessage); + assertArrayEquals("Invalid result", body, result); + } + + @Test + public void write() throws IOException { + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); + byte[] body = new byte[]{0x1, 0x2}; + converter.write(body, outputMessage); + assertArrayEquals("Invalid result", body, outputMessage.getBodyAsBytes()); + assertEquals("Invalid content-type", new MediaType("application", "octet-stream"), + outputMessage.getHeaders().getContentType()); + assertEquals("Invalid content-length", 2, outputMessage.getHeaders().getContentLength()); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/web/converter/StringHttpMessageConverterTests.java b/org.springframework.web/src/test/java/org/springframework/web/converter/StringHttpMessageConverterTests.java new file mode 100644 index 00000000000..af6dd9328f3 --- /dev/null +++ b/org.springframework.web/src/test/java/org/springframework/web/converter/StringHttpMessageConverterTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.converter; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Collections; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.util.MediaType; +import org.springframework.web.http.MockHttpInputMessage; +import org.springframework.web.http.MockHttpOutputMessage; + +/** + * @author Arjen Poutsma + */ +public class StringHttpMessageConverterTests { + + private StringHttpMessageConverter converter; + + @Before + public void setUp() { + converter = new StringHttpMessageConverter(); + } + + @Test + public void read() throws IOException { + String body = "Hello World"; + Charset charset = Charset.forName("UTF-8"); + MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(charset)); + inputMessage.getHeaders().setContentType(new MediaType("text", "plain", charset)); + String result = converter.read(String.class, inputMessage); + assertEquals("Invalid result", body, result); + } + + @Test + public void write() throws IOException { + Charset charset = Charset.forName("UTF-8"); + converter.setSupportedMediaTypes(Collections.singletonList(new MediaType("text", "plain", charset))); + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); + String body = "HŽllo W¿rld"; + converter.write(body, outputMessage); + assertEquals("Invalid result", body, outputMessage.getBodyAsString(charset)); + assertEquals("Invalid content-type", new MediaType("text", "plain", charset), + outputMessage.getHeaders().getContentType()); + assertEquals("Invalid content-length", 13, outputMessage.getHeaders().getContentLength()); + assertFalse("Invalid accept-charset", outputMessage.getHeaders().getAcceptCharset().isEmpty()); + } +} diff --git a/org.springframework.web/src/test/java/org/springframework/web/http/HttpHeadersTests.java b/org.springframework.web/src/test/java/org/springframework/web/http/HttpHeadersTests.java index 9d2bc4e1eae..e4ec4a82880 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/http/HttpHeadersTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/http/HttpHeadersTests.java @@ -50,7 +50,19 @@ public class HttpHeadersTests { mediaTypes.add(mediaType2); headers.setAccept(mediaTypes); assertEquals("Invalid Accept header", mediaTypes, headers.getAccept()); - assertEquals("Invalid Accept header", "text/html,text/plain", headers.getFirst("Accept")); + assertEquals("Invalid Accept header", "text/html, text/plain", headers.getFirst("Accept")); + } + + @Test + public void acceptCharsets() { + Charset charset1 = Charset.forName("UTF-8"); + Charset charset2 = Charset.forName("ISO-8859-1"); + List charsets = new ArrayList(2); + charsets.add(charset1); + charsets.add(charset2); + headers.setAcceptCharset(charsets); + assertEquals("Invalid Accept header", charsets, headers.getAcceptCharset()); + assertEquals("Invalid Accept header", "utf-8, iso-8859-1", headers.getFirst("Accept-Charset")); } @Test