From d14cc0d7a20326fb5643dd966af71d2691a376da Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Fri, 27 Mar 2009 17:43:29 +0000 Subject: [PATCH] - Renamed writeToInternal to writeInternal - Added separate exceptions for reading and writing HttpMessages --- .../AbstractHttpMessageConverter.java | 29 ++++----- .../ByteArrayHttpMessageConverter.java | 10 ++- .../converter/FormHttpMessageConverter.java | 7 +-- .../HttpMessageConversionException.java | 6 +- .../HttpMessageNotReadableException.java | 46 ++++++++++++++ .../HttpMessageNotWritableException.java | 46 ++++++++++++++ .../converter/StringHttpMessageConverter.java | 7 +-- .../xml/AbstractXmlHttpMessageConverter.java | 17 ++--- .../xml/MarshallingHttpMessageConverter.java | 34 +++++++++- .../xml/SourceHttpMessageConverter.java | 63 ++++++++++++++----- 10 files changed, 203 insertions(+), 62 deletions(-) create mode 100644 org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java create mode 100644 org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotWritableException.java diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java index 5d990a2528..116ecf60dc 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java @@ -25,10 +25,10 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; +import org.springframework.util.Assert; /** * Abstract base class for most {@link HttpMessageConverter} implementations. @@ -47,32 +47,25 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv private List supportedMediaTypes = Collections.emptyList(); - /** * Construct an {@code AbstractHttpMessageConverter} with no supported media types. + * * @see #setSupportedMediaTypes */ protected AbstractHttpMessageConverter() { } - /** - * Construct an {@code AbstractHttpMessageConverter} with one supported media type. - */ + /** Construct an {@code AbstractHttpMessageConverter} with one supported media type. */ protected AbstractHttpMessageConverter(MediaType supportedMediaType) { this.supportedMediaTypes = Collections.singletonList(supportedMediaType); } - /** - * Construct an {@code AbstractHttpMessageConverter} with multiple supported media type. - */ + /** Construct an {@code AbstractHttpMessageConverter} with multiple supported media type. */ protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) { this.supportedMediaTypes = Arrays.asList(supportedMediaTypes); } - - /** - * Set the list of {@link MediaType} objects supported by this converter. - */ + /** Set 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); @@ -85,7 +78,8 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv /** *

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)}. + * {@link #writeInternal(Object, HttpOutputMessage)}. + * * @throws HttpMessageConversionException in case of conversion errors */ public final void write(T t, HttpOutputMessage outputMessage) throws IOException { @@ -98,7 +92,7 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv if (contentLength != null) { headers.setContentLength(contentLength); } - writeToInternal(t, outputMessage); + writeInternal(t, outputMessage); outputMessage.getBody().flush(); } @@ -106,6 +100,7 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv * 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 */ @@ -117,6 +112,7 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv /** * 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 */ @@ -126,11 +122,12 @@ public abstract class AbstractHttpMessageConverter implements HttpMessageConv /** * 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 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; + protected abstract void writeInternal(T t, HttpOutputMessage outputMessage) throws IOException; } diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java index 8551f29cd8..5e56f4cb08 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/ByteArrayHttpMessageConverter.java @@ -19,10 +19,10 @@ package org.springframework.http.converter; import java.io.ByteArrayOutputStream; import java.io.IOException; -import org.springframework.util.FileCopyUtils; -import org.springframework.http.MediaType; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.util.FileCopyUtils; /** * Implementation of {@link HttpMessageConverter} that can read and write byte arrays. @@ -37,9 +37,7 @@ import org.springframework.http.HttpOutputMessage; */ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter { - /** - * Creates a new instance of the {@code ByteArrayHttpMessageConverter}. - */ + /** Creates a new instance of the {@code ByteArrayHttpMessageConverter}. */ public ByteArrayHttpMessageConverter() { super(MediaType.ALL); } @@ -71,7 +69,7 @@ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter< } @Override - protected void writeToInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException { + protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException { FileCopyUtils.copy(bytes, outputMessage.getBody()); } diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java index bd2ed2507b..6d935aef7a 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java @@ -40,6 +40,7 @@ import org.springframework.util.StringUtils; *

By default, this converter reads and writes the media type ({@code application/x-www-form-urlencoded}). This * can be overridden by setting the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} property. Form * data is read from and written into a {@link MultiValueMap MultiValueMap<String, String>}. + * * @author Arjen Poutsma * @see MultiValueMap * @since 3.0 @@ -48,9 +49,7 @@ public class FormHttpMessageConverter extends AbstractHttpMessageConverter form, HttpOutputMessage outputMessage) + protected void writeInternal(MultiValueMap form, HttpOutputMessage outputMessage) throws IOException { MediaType contentType = getContentType(form); Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET; diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageConversionException.java b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageConversionException.java index f7120c6e27..8f0cedc125 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageConversionException.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageConversionException.java @@ -27,7 +27,8 @@ import org.springframework.core.NestedRuntimeException; public class HttpMessageConversionException extends NestedRuntimeException { /** - * Create a new MessageConversionException. + * Create a new HttpMessageConversionException. + * * @param msg the detail message */ public HttpMessageConversionException(String msg) { @@ -35,7 +36,8 @@ public class HttpMessageConversionException extends NestedRuntimeException { } /** - * Create a new MessageConversionException. + * Create a new HttpMessageConversionException. + * * @param msg the detail message * @param cause the root cause (if any) */ diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java new file mode 100644 index 0000000000..cba5bbe909 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java @@ -0,0 +1,46 @@ +/* + * 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.http.converter; + +/** + * Thrown by {@link HttpMessageConverter} implementations when the + * {@link HttpMessageConverter#read(Class, org.springframework.http.HttpInputMessage) read} method fails. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class HttpMessageNotReadableException extends HttpMessageConversionException { + + /** + * Create a new HttpMessageNotReadableException. + * + * @param msg the detail message + */ + public HttpMessageNotReadableException(String msg) { + super(msg); + } + + /** + * Create a new HttpMessageNotReadableException. + * + * @param msg the detail message + * @param cause the root cause (if any) + */ + public HttpMessageNotReadableException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotWritableException.java b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotWritableException.java new file mode 100644 index 0000000000..5e6580b392 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/HttpMessageNotWritableException.java @@ -0,0 +1,46 @@ +/* + * 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.http.converter; + +/** + * Thrown by {@link org.springframework.http.converter.HttpMessageConverter} implementations when the + * {@link org.springframework.http.converter.HttpMessageConverter#write(Object, org.springframework.http.HttpOutputMessage) write} method fails. + * + * @author Arjen Poutsma + * @since 3.0 + */ +public class HttpMessageNotWritableException extends HttpMessageConversionException { + + /** + * Create a new HttpMessageNotWritableException. + * + * @param msg the detail message + */ + public HttpMessageNotWritableException(String msg) { + super(msg); + } + + /** + * Create a new HttpMessageNotWritableException. + * + * @param msg the detail message + * @param cause the root cause (if any) + */ + public HttpMessageNotWritableException(String msg, Throwable cause) { + super(msg, cause); + } +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java index 9ad1563ad2..2e39061c5a 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java @@ -24,10 +24,10 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import org.springframework.util.FileCopyUtils; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; +import org.springframework.util.FileCopyUtils; /** * Implementation of {@link HttpMessageConverter} that can read and write strings. @@ -45,13 +45,11 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter availableCharsets; - public StringHttpMessageConverter() { super(new MediaType("text", "plain", DEFAULT_CHARSET), new MediaType("text", "*")); this.availableCharsets = new ArrayList(Charset.availableCharsets().values()); } - public boolean supports(Class clazz) { return String.class.equals(clazz); } @@ -80,7 +78,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverterBy default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses. + * * @return the list of accepted charsets */ protected List getAcceptedCharsets() { diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java index bb8af50284..373aafed8b 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * 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. @@ -72,12 +72,12 @@ public abstract class AbstractXmlHttpMessageConverter extends AbstractHttpMes protected abstract T readFromSource(Class clazz, HttpHeaders headers, Source source) throws IOException; @Override - protected final void writeToInternal(T t, HttpOutputMessage outputMessage) throws IOException { + protected final void writeInternal(T t, HttpOutputMessage outputMessage) throws IOException { writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody())); } /** - * Abstract template method called from {@link #writeToInternal(Object, HttpOutputMessage)}. + * Abstract template method called from {@link #writeInternal(Object, HttpOutputMessage)}. * * @param t the object to write to the output message * @param headers the HTTP output headers @@ -94,14 +94,9 @@ public abstract class AbstractXmlHttpMessageConverter extends AbstractHttpMes * @param result the result to transform to * @throws HttpMessageConversionException in case of transformation errors */ - protected void transform(Source source, Result result) { - try { - Transformer transformer = transformerFactory.newTransformer(); - transformer.transform(source, result); - } - catch (TransformerException ex) { - throw new HttpMessageConversionException("Could not transform XML", ex); - } + protected void transform(Source source, Result result) throws TransformerException { + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(source, result); } } diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java index 15231b57da..e28d055e47 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java @@ -1,3 +1,19 @@ +/* + * 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.http.converter.xml; import java.io.IOException; @@ -6,8 +22,12 @@ import javax.xml.transform.Source; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.HttpHeaders; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.oxm.Marshaller; +import org.springframework.oxm.MarshallingFailureException; import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.UnmarshallingFailureException; import org.springframework.util.Assert; /** @@ -98,11 +118,21 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve @Override protected Object readFromSource(Class clazz, HttpHeaders headers, Source source) throws IOException { - return unmarshaller.unmarshal(source); + try { + return unmarshaller.unmarshal(source); + } + catch (UnmarshallingFailureException ex) { + throw new HttpMessageNotReadableException("Could not read [" + clazz + "]", ex); + } } @Override protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException { - marshaller.marshal(o, result); + try { + marshaller.marshal(o, result); + } + catch (MarshallingFailureException ex) { + throw new HttpMessageNotWritableException("Could not write [" + o + "]", ex); + } } } diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java index 3546978b41..e79e2b9a16 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java @@ -1,3 +1,19 @@ +/* + * 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.http.converter.xml; import java.io.ByteArrayInputStream; @@ -5,6 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.xml.transform.Result; import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; @@ -15,6 +32,8 @@ import org.xml.sax.InputSource; import org.springframework.http.HttpHeaders; import org.springframework.http.converter.HttpMessageConversionException; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; /** @author Arjen Poutsma */ public class SourceHttpMessageConverter extends AbstractXmlHttpMessageConverter { @@ -26,26 +45,31 @@ public class SourceHttpMessageConverter extends AbstractXmlHtt @Override @SuppressWarnings("unchecked") protected T readFromSource(Class clazz, HttpHeaders headers, Source source) throws IOException { - if (DOMSource.class.equals(clazz)) { - DOMResult domResult = new DOMResult(); - transform(source, domResult); - return (T) new DOMSource(domResult.getNode()); - } - else if (SAXSource.class.equals(clazz)) { - ByteArrayInputStream bis = transformToByteArray(source); - return (T) new SAXSource(new InputSource(bis)); - } - else if (StreamSource.class.equals(clazz) || Source.class.equals(clazz)) { - ByteArrayInputStream bis = transformToByteArray(source); - return (T) new StreamSource(bis); + try { + if (DOMSource.class.equals(clazz)) { + DOMResult domResult = new DOMResult(); + transform(source, domResult); + return (T) new DOMSource(domResult.getNode()); + } + else if (SAXSource.class.equals(clazz)) { + ByteArrayInputStream bis = transformToByteArray(source); + return (T) new SAXSource(new InputSource(bis)); + } + else if (StreamSource.class.equals(clazz) || Source.class.equals(clazz)) { + ByteArrayInputStream bis = transformToByteArray(source); + return (T) new StreamSource(bis); + } + else { + throw new HttpMessageConversionException("Could not read class [" + clazz + + "]. Only DOMSource, SAXSource, and StreamSource are supported."); + } } - else { - throw new HttpMessageConversionException( - "Could not read class [" + clazz + "]. Only DOMSource, SAXSource, and StreamSource are supported."); + catch (TransformerException ex) { + throw new HttpMessageNotReadableException("Could not transform from [" + source + "]", ex); } } - private ByteArrayInputStream transformToByteArray(Source source) { + private ByteArrayInputStream transformToByteArray(Source source) throws TransformerException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); transform(source, new StreamResult(bos)); return new ByteArrayInputStream(bos.toByteArray()); @@ -53,6 +77,11 @@ public class SourceHttpMessageConverter extends AbstractXmlHtt @Override protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException { - transform(t, result); + try { + transform(t, result); + } + catch (TransformerException ex) { + throw new HttpMessageNotWritableException("Could not transform [" + t + "] to [" + result + "]", ex); + } } }