Browse Source

HttpMessageNotReadableException provides access to HttpInputMessage

Issue: SPR-15588
pull/1870/head
Juergen Hoeller 6 years ago
parent
commit
83faee67d5
  1. 5
      spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java
  2. 48
      spring-web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java
  3. 3
      spring-web/src/main/java/org/springframework/http/converter/ObjectToStringHttpMessageConverter.java
  4. 2
      spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java
  5. 2
      spring-web/src/main/java/org/springframework/http/converter/feed/AbstractWireFeedHttpMessageConverter.java
  6. 2
      spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java
  7. 2
      spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java
  8. 21
      spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java
  9. 35
      spring-web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java
  10. 12
      spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java
  11. 13
      spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java
  12. 32
      spring-web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java
  13. 30
      spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
  14. 12
      spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java
  15. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java
  16. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java

5
spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java

@ -172,7 +172,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B @@ -172,7 +172,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
imageInputStream = createImageInputStream(inputMessage.getBody());
MediaType contentType = inputMessage.getHeaders().getContentType();
if (contentType == null) {
throw new HttpMessageNotReadableException("No Content-Type header");
throw new HttpMessageNotReadableException("No Content-Type header", inputMessage);
}
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
if (imageReaders.hasNext()) {
@ -184,7 +184,8 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B @@ -184,7 +184,8 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
else {
throw new HttpMessageNotReadableException(
"Could not find javax.imageio.ImageReader for Content-Type [" + contentType + "]");
"Could not find javax.imageio.ImageReader for Content-Type [" + contentType + "]",
inputMessage);
}
}
finally {

48
spring-web/src/main/java/org/springframework/http/converter/HttpMessageNotReadableException.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 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.
@ -16,33 +16,79 @@ @@ -16,33 +16,79 @@
package org.springframework.http.converter;
import org.springframework.http.HttpInputMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Thrown by {@link HttpMessageConverter} implementations when the
* {@link HttpMessageConverter#read} method fails.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
*/
@SuppressWarnings("serial")
public class HttpMessageNotReadableException extends HttpMessageConversionException {
@Nullable
private final HttpInputMessage httpInputMessage;
/**
* Create a new HttpMessageNotReadableException.
* @param msg the detail message
* @deprecated as of 5.1, in favor of {@link #HttpMessageNotReadableException(String, HttpInputMessage)}
*/
@Deprecated
public HttpMessageNotReadableException(String msg) {
super(msg);
this.httpInputMessage = null;
}
/**
* Create a new HttpMessageNotReadableException.
* @param msg the detail message
* @param cause the root cause (if any)
* @deprecated as of 5.1, in favor of {@link #HttpMessageNotReadableException(String, Throwable, HttpInputMessage)}
*/
@Deprecated
public HttpMessageNotReadableException(String msg, @Nullable Throwable cause) {
super(msg, cause);
this.httpInputMessage = null;
}
/**
* Create a new HttpMessageNotReadableException.
* @param msg the detail message
* @param httpInputMessage the original HTTP message
* @since 5.1
*/
public HttpMessageNotReadableException(String msg, HttpInputMessage httpInputMessage) {
super(msg);
this.httpInputMessage = httpInputMessage;
}
/**
* Create a new HttpMessageNotReadableException.
* @param msg the detail message
* @param cause the root cause (if any)
* @param httpInputMessage the original HTTP message
* @since 5.1
*/
public HttpMessageNotReadableException(String msg, @Nullable Throwable cause, HttpInputMessage httpInputMessage) {
super(msg, cause);
this.httpInputMessage = httpInputMessage;
}
/**
* Return the original HTTP message.
* @since 5.1
*/
public HttpInputMessage getHttpInputMessage() {
Assert.state(this.httpInputMessage != null, "No HttpInputMessage available - use non-deprecated constructors");
return this.httpInputMessage;
}
}

3
spring-web/src/main/java/org/springframework/http/converter/ObjectToStringHttpMessageConverter.java

@ -113,7 +113,8 @@ public class ObjectToStringHttpMessageConverter extends AbstractHttpMessageConve @@ -113,7 +113,8 @@ public class ObjectToStringHttpMessageConverter extends AbstractHttpMessageConve
Object result = this.conversionService.convert(value, clazz);
if (result == null) {
throw new HttpMessageNotReadableException(
"Unexpected null conversion result for '" + value + "' to " + clazz);
"Unexpected null conversion result for '" + value + "' to " + clazz,
inputMessage);
}
return result;
}

2
spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java

@ -97,7 +97,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R @@ -97,7 +97,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
};
}
else {
throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz);
throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz, inputMessage);
}
}

2
spring-web/src/main/java/org/springframework/http/converter/feed/AbstractWireFeedHttpMessageConverter.java

@ -78,7 +78,7 @@ public abstract class AbstractWireFeedHttpMessageConverter<T extends WireFeed> @@ -78,7 +78,7 @@ public abstract class AbstractWireFeedHttpMessageConverter<T extends WireFeed>
return (T) feedInput.build(reader);
}
catch (FeedException ex) {
throw new HttpMessageNotReadableException("Could not read WireFeed: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException("Could not read WireFeed: " + ex.getMessage(), ex, inputMessage);
}
}

2
spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java

@ -242,7 +242,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener @@ -242,7 +242,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex);
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
}
}

2
spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java

@ -109,7 +109,7 @@ public abstract class AbstractJsonHttpMessageConverter extends AbstractGenericHt @@ -109,7 +109,7 @@ public abstract class AbstractJsonHttpMessageConverter extends AbstractGenericHt
return readInternal(resolvedType, reader);
}
catch (Exception ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex, inputMessage);
}
}

21
spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java

@ -273,12 +273,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -273,12 +273,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder)
throws IOException, HttpMessageNotReadableException;
throws IOException, HttpMessageConversionException;
void print(Message message, OutputStream output, MediaType contentType, Charset charset)
throws IOException, HttpMessageNotWritableException;
throws IOException, HttpMessageConversionException;
}
/**
* {@link ProtobufFormatSupport} implementation used when
* {@code com.googlecode.protobuf.format.FormatFactory} is available.
@ -311,7 +312,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -311,7 +312,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
@Override
public void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder)
throws IOException, HttpMessageNotReadableException {
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
this.jsonFormatter.merge(input, charset, extensionRegistry, builder);
@ -320,14 +321,14 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -320,14 +321,14 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
this.xmlFormatter.merge(input, charset, extensionRegistry, builder);
}
else {
throw new HttpMessageNotReadableException(
throw new HttpMessageConversionException(
"protobuf-java-format does not support parsing " + contentType);
}
}
@Override
public void print(Message message, OutputStream output, MediaType contentType, Charset charset)
throws IOException, HttpMessageNotWritableException {
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
this.jsonFormatter.print(message, output, charset);
@ -339,7 +340,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -339,7 +340,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
this.htmlFormatter.print(message, output, charset);
}
else {
throw new HttpMessageNotWritableException(
throw new HttpMessageConversionException(
"protobuf-java-format does not support printing " + contentType);
}
}
@ -374,21 +375,21 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -374,21 +375,21 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
@Override
public void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder)
throws IOException, HttpMessageNotReadableException {
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
InputStreamReader reader = new InputStreamReader(input, charset);
this.parser.merge(reader, builder);
}
else {
throw new HttpMessageNotReadableException(
throw new HttpMessageConversionException(
"protobuf-java-util does not support parsing " + contentType);
}
}
@Override
public void print(Message message, OutputStream output, MediaType contentType, Charset charset)
throws IOException, HttpMessageNotWritableException {
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
OutputStreamWriter writer = new OutputStreamWriter(output, charset);
@ -396,7 +397,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -396,7 +397,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
writer.flush();
}
else {
throw new HttpMessageNotWritableException(
throw new HttpMessageConversionException(
"protobuf-java-util does not support printing " + contentType);
}
}

35
spring-web/src/main/java/org/springframework/http/converter/xml/AbstractXmlHttpMessageConverter.java

@ -29,6 +29,7 @@ import org.springframework.http.HttpInputMessage; @@ -29,6 +29,7 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
@ -41,6 +42,7 @@ import org.springframework.http.converter.HttpMessageNotWritableException; @@ -41,6 +42,7 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
* supportedMediaTypes} property.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
* @param <T> the converted object type
*/
@ -62,14 +64,31 @@ public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMes @@ -62,14 +64,31 @@ public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMes
public final T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody()));
try {
return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody()));
}
catch (IOException | HttpMessageConversionException ex) {
throw ex;
}
catch (Exception ex) {
throw new HttpMessageNotReadableException("Could not unmarshal to [" + clazz + "]: " + ex.getMessage(),
ex, inputMessage);
}
}
@Override
protected final void writeInternal(T t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody()));
try {
writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody()));
}
catch (IOException | HttpMessageConversionException ex) {
throw ex;
}
catch (Exception ex) {
throw new HttpMessageNotWritableException("Could not marshal [" + t + "]: " + ex.getMessage(), ex);
}
}
/**
@ -89,21 +108,17 @@ public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMes @@ -89,21 +108,17 @@ public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMes
* @param headers the HTTP input headers
* @param source the HTTP input body
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
* @throws Exception in case of I/O or conversion errors
*/
protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source)
throws IOException, HttpMessageNotReadableException;
protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws Exception;
/**
* 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
* @param result the HTTP output body
* @throws IOException in case of I/O errors
* @throws HttpMessageNotWritableException in case of conversion errors
* @throws Exception in case of I/O or conversion errors
*/
protected abstract void writeToResult(T t, HttpHeaders headers, Result result)
throws IOException, HttpMessageNotWritableException;
protected abstract void writeToResult(T t, HttpHeaders headers, Result result) throws Exception;
}

12
spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java

@ -132,7 +132,7 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection> @@ -132,7 +132,7 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
}
@Override
protected T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws IOException {
protected T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws Exception {
// should not be called, since we return false for canRead(Class)
throw new UnsupportedOperationException();
}
@ -160,18 +160,20 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection> @@ -160,18 +160,20 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
}
else {
// should not happen, since we check in canRead(Type)
throw new HttpMessageNotReadableException("Cannot unmarshal to [" + elementClass + "]");
throw new HttpMessageNotReadableException(
"Cannot unmarshal to [" + elementClass + "]", inputMessage);
}
event = moveToNextElement(streamReader);
}
return result;
}
catch (XMLStreamException ex) {
throw new HttpMessageNotReadableException("Failed to read XML stream: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException(
"Failed to read XML stream: " + ex.getMessage(), ex, inputMessage);
}
catch (UnmarshalException ex) {
throw new HttpMessageNotReadableException(
"Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex);
"Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex, inputMessage);
}
catch (JAXBException ex) {
throw new HttpMessageConversionException("Invalid JAXB setup: " + ex.getMessage(), ex);
@ -237,7 +239,7 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection> @@ -237,7 +239,7 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
}
@Override
protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException {
protected void writeToResult(T t, HttpHeaders headers, Result result) throws Exception {
throw new UnsupportedOperationException();
}

13
spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java

@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
package org.springframework.http.converter.xml;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
@ -41,8 +40,6 @@ import org.springframework.core.annotation.AnnotationUtils; @@ -41,8 +40,6 @@ import org.springframework.core.annotation.AnnotationUtils;
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;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@ -124,7 +121,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -124,7 +121,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
}
@Override
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException {
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws Exception {
try {
source = processSource(source);
Unmarshaller unmarshaller = createUnmarshaller(clazz);
@ -138,13 +135,13 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -138,13 +135,13 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
}
catch (NullPointerException ex) {
if (!isSupportDtd()) {
throw new HttpMessageNotReadableException("NPE while unmarshalling. " +
throw new IllegalStateException("NPE while unmarshalling. " +
"This can happen due to the presence of DTD declarations which are disabled.", ex);
}
throw ex;
}
catch (UnmarshalException ex) {
throw new HttpMessageNotReadableException("Could not unmarshal to [" + clazz + "]: " + ex.getMessage(), ex);
throw ex;
}
catch (JAXBException ex) {
throw new HttpMessageConversionException("Invalid JAXB setup: " + ex.getMessage(), ex);
@ -177,7 +174,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -177,7 +174,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
}
@Override
protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException {
protected void writeToResult(Object o, HttpHeaders headers, Result result) throws Exception {
try {
Class<?> clazz = ClassUtils.getUserClass(o);
Marshaller marshaller = createMarshaller(clazz);
@ -185,7 +182,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -185,7 +182,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
marshaller.marshal(o, result);
}
catch (MarshalException ex) {
throw new HttpMessageNotWritableException("Could not marshal [" + o + "]: " + ex.getMessage(), ex);
throw ex;
}
catch (JAXBException ex) {
throw new HttpMessageConversionException("Invalid JAXB setup: " + ex.getMessage(), ex);

32
spring-web/src/main/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@ -16,20 +16,15 @@ @@ -16,20 +16,15 @@
package org.springframework.http.converter.xml;
import java.io.IOException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
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;
/**
@ -125,28 +120,19 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve @@ -125,28 +120,19 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
}
@Override
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException {
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws Exception {
Assert.notNull(this.unmarshaller, "Property 'unmarshaller' is required");
try {
Object result = this.unmarshaller.unmarshal(source);
if (!clazz.isInstance(result)) {
throw new TypeMismatchException(result, clazz);
}
return result;
}
catch (UnmarshallingFailureException ex) {
throw new HttpMessageNotReadableException("Could not read [" + clazz + "]", ex);
Object result = this.unmarshaller.unmarshal(source);
if (!clazz.isInstance(result)) {
throw new TypeMismatchException(result, clazz);
}
return result;
}
@Override
protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException {
protected void writeToResult(Object o, HttpHeaders headers, Result result) throws Exception {
Assert.notNull(this.marshaller, "Property 'marshaller' is required");
try {
this.marshaller.marshal(o, result);
}
catch (MarshallingFailureException ex) {
throw new HttpMessageNotWritableException("Could not write [" + o + "]", ex);
}
this.marshaller.marshal(o, result);
}
}

30
spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java

@ -147,24 +147,24 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -147,24 +147,24 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
InputStream body = inputMessage.getBody();
if (DOMSource.class == clazz) {
return (T) readDOMSource(body);
return (T) readDOMSource(body, inputMessage);
}
else if (SAXSource.class == clazz) {
return (T) readSAXSource(body);
return (T) readSAXSource(body, inputMessage);
}
else if (StAXSource.class == clazz) {
return (T) readStAXSource(body);
return (T) readStAXSource(body, inputMessage);
}
else if (StreamSource.class == clazz || Source.class == clazz) {
return (T) readStreamSource(body);
}
else {
throw new HttpMessageNotReadableException("Could not read class [" + clazz +
"]. Only DOMSource, SAXSource, StAXSource, and StreamSource are supported.");
"]. Only DOMSource, SAXSource, StAXSource, and StreamSource are supported.", inputMessage);
}
}
private DOMSource readDOMSource(InputStream body) throws IOException {
private DOMSource readDOMSource(InputStream body, HttpInputMessage inputMessage) throws IOException {
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
@ -181,21 +181,23 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -181,21 +181,23 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
}
catch (NullPointerException ex) {
if (!isSupportDtd()) {
throw new HttpMessageNotReadableException("NPE while unmarshalling: " +
"This can happen due to the presence of DTD declarations which are disabled.", ex);
throw new HttpMessageNotReadableException("NPE while unmarshalling: This can happen " +
"due to the presence of DTD declarations which are disabled.", ex, inputMessage);
}
throw ex;
}
catch (ParserConfigurationException ex) {
throw new HttpMessageNotReadableException("Could not set feature: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException(
"Could not set feature: " + ex.getMessage(), ex, inputMessage);
}
catch (SAXException ex) {
throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException(
"Could not parse document: " + ex.getMessage(), ex, inputMessage);
}
}
@SuppressWarnings("deprecation") // on JDK 9
private SAXSource readSAXSource(InputStream body) throws IOException {
private SAXSource readSAXSource(InputStream body, HttpInputMessage inputMessage) throws IOException {
try {
XMLReader xmlReader = org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
@ -207,11 +209,12 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -207,11 +209,12 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
return new SAXSource(xmlReader, new InputSource(new ByteArrayInputStream(bytes)));
}
catch (SAXException ex) {
throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException(
"Could not parse document: " + ex.getMessage(), ex, inputMessage);
}
}
private Source readStAXSource(InputStream body) {
private Source readStAXSource(InputStream body, HttpInputMessage inputMessage) {
try {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, isSupportDtd());
@ -223,7 +226,8 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -223,7 +226,8 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
return new StAXSource(streamReader);
}
catch (XMLStreamException ex) {
throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
throw new HttpMessageNotReadableException(
"Could not parse document: " + ex.getMessage(), ex, inputMessage);
}
}

12
spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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.
@ -87,7 +87,7 @@ public class MarshallingHttpMessageConverterTests { @@ -87,7 +87,7 @@ public class MarshallingHttpMessageConverterTests {
assertEquals("Invalid result", body, result);
}
@Test(expected = TypeMismatchException.class)
@Test
public void readWithTypeMismatchException() throws Exception {
MockHttpInputMessage inputMessage = new MockHttpInputMessage(new byte[0]);
@ -96,7 +96,13 @@ public class MarshallingHttpMessageConverterTests { @@ -96,7 +96,13 @@ public class MarshallingHttpMessageConverterTests {
given(unmarshaller.unmarshal(isA(StreamSource.class))).willReturn(Integer.valueOf(3));
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter(marshaller, unmarshaller);
converter.read(String.class, inputMessage);
try {
converter.read(String.class, inputMessage);
fail("Should have thrown HttpMessageNotReadableException");
}
catch (HttpMessageNotReadableException ex) {
assertTrue(ex.getCause() instanceof TypeMismatchException);
}
}
@Test

2
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java

@ -212,7 +212,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements @@ -212,7 +212,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
if (body == NO_VALUE) {

2
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java

@ -157,7 +157,7 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter @@ -157,7 +157,7 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString());
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}

Loading…
Cancel
Save