Skip to content

Commit 83faee6

Browse files
committed
HttpMessageNotReadableException provides access to HttpInputMessage
Issue: SPR-15588
1 parent fc699b2 commit 83faee6

16 files changed

+141
-82
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public BufferedImage read(@Nullable Class<? extends BufferedImage> clazz, HttpIn
172172
imageInputStream = createImageInputStream(inputMessage.getBody());
173173
MediaType contentType = inputMessage.getHeaders().getContentType();
174174
if (contentType == null) {
175-
throw new HttpMessageNotReadableException("No Content-Type header");
175+
throw new HttpMessageNotReadableException("No Content-Type header", inputMessage);
176176
}
177177
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
178178
if (imageReaders.hasNext()) {
@@ -184,7 +184,8 @@ public BufferedImage read(@Nullable Class<? extends BufferedImage> clazz, HttpIn
184184
}
185185
else {
186186
throw new HttpMessageNotReadableException(
187-
"Could not find javax.imageio.ImageReader for Content-Type [" + contentType + "]");
187+
"Could not find javax.imageio.ImageReader for Content-Type [" + contentType + "]",
188+
inputMessage);
188189
}
189190
}
190191
finally {

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,33 +16,79 @@
1616

1717
package org.springframework.http.converter;
1818

19+
import org.springframework.http.HttpInputMessage;
1920
import org.springframework.lang.Nullable;
21+
import org.springframework.util.Assert;
2022

2123
/**
2224
* Thrown by {@link HttpMessageConverter} implementations when the
2325
* {@link HttpMessageConverter#read} method fails.
2426
*
2527
* @author Arjen Poutsma
28+
* @author Juergen Hoeller
2629
* @since 3.0
2730
*/
2831
@SuppressWarnings("serial")
2932
public class HttpMessageNotReadableException extends HttpMessageConversionException {
3033

34+
@Nullable
35+
private final HttpInputMessage httpInputMessage;
36+
37+
3138
/**
3239
* Create a new HttpMessageNotReadableException.
3340
* @param msg the detail message
41+
* @deprecated as of 5.1, in favor of {@link #HttpMessageNotReadableException(String, HttpInputMessage)}
3442
*/
43+
@Deprecated
3544
public HttpMessageNotReadableException(String msg) {
3645
super(msg);
46+
this.httpInputMessage = null;
3747
}
3848

3949
/**
4050
* Create a new HttpMessageNotReadableException.
4151
* @param msg the detail message
4252
* @param cause the root cause (if any)
53+
* @deprecated as of 5.1, in favor of {@link #HttpMessageNotReadableException(String, Throwable, HttpInputMessage)}
4354
*/
55+
@Deprecated
4456
public HttpMessageNotReadableException(String msg, @Nullable Throwable cause) {
4557
super(msg, cause);
58+
this.httpInputMessage = null;
59+
}
60+
61+
/**
62+
* Create a new HttpMessageNotReadableException.
63+
* @param msg the detail message
64+
* @param httpInputMessage the original HTTP message
65+
* @since 5.1
66+
*/
67+
public HttpMessageNotReadableException(String msg, HttpInputMessage httpInputMessage) {
68+
super(msg);
69+
this.httpInputMessage = httpInputMessage;
70+
}
71+
72+
/**
73+
* Create a new HttpMessageNotReadableException.
74+
* @param msg the detail message
75+
* @param cause the root cause (if any)
76+
* @param httpInputMessage the original HTTP message
77+
* @since 5.1
78+
*/
79+
public HttpMessageNotReadableException(String msg, @Nullable Throwable cause, HttpInputMessage httpInputMessage) {
80+
super(msg, cause);
81+
this.httpInputMessage = httpInputMessage;
82+
}
83+
84+
85+
/**
86+
* Return the original HTTP message.
87+
* @since 5.1
88+
*/
89+
public HttpInputMessage getHttpInputMessage() {
90+
Assert.state(this.httpInputMessage != null, "No HttpInputMessage available - use non-deprecated constructors");
91+
return this.httpInputMessage;
4692
}
4793

4894
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
113113
Object result = this.conversionService.convert(value, clazz);
114114
if (result == null) {
115115
throw new HttpMessageNotReadableException(
116-
"Unexpected null conversion result for '" + value + "' to " + clazz);
116+
"Unexpected null conversion result for '" + value + "' to " + clazz,
117+
inputMessage);
117118
}
118119
return result;
119120
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public String getFilename() {
9797
};
9898
}
9999
else {
100-
throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz);
100+
throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz, inputMessage);
101101
}
102102
}
103103

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage
7878
return (T) feedInput.build(reader);
7979
}
8080
catch (FeedException ex) {
81-
throw new HttpMessageNotReadableException("Could not read WireFeed: " + ex.getMessage(), ex);
81+
throw new HttpMessageNotReadableException("Could not read WireFeed: " + ex.getMessage(), ex, inputMessage);
8282
}
8383
}
8484

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) th
242242
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
243243
}
244244
catch (JsonProcessingException ex) {
245-
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex);
245+
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
246246
}
247247
}
248248

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ private Object readResolved(Type resolvedType, HttpInputMessage inputMessage)
109109
return readInternal(resolvedType, reader);
110110
}
111111
catch (Exception ex) {
112-
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
112+
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex, inputMessage);
113113
}
114114
}
115115

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,13 @@ interface ProtobufFormatSupport {
273273

274274
void merge(InputStream input, Charset charset, MediaType contentType,
275275
ExtensionRegistry extensionRegistry, Message.Builder builder)
276-
throws IOException, HttpMessageNotReadableException;
276+
throws IOException, HttpMessageConversionException;
277277

278278
void print(Message message, OutputStream output, MediaType contentType, Charset charset)
279-
throws IOException, HttpMessageNotWritableException;
279+
throws IOException, HttpMessageConversionException;
280280
}
281281

282+
282283
/**
283284
* {@link ProtobufFormatSupport} implementation used when
284285
* {@code com.googlecode.protobuf.format.FormatFactory} is available.
@@ -311,7 +312,7 @@ public boolean supportsWriteOnly(@Nullable MediaType mediaType) {
311312
@Override
312313
public void merge(InputStream input, Charset charset, MediaType contentType,
313314
ExtensionRegistry extensionRegistry, Message.Builder builder)
314-
throws IOException, HttpMessageNotReadableException {
315+
throws IOException, HttpMessageConversionException {
315316

316317
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
317318
this.jsonFormatter.merge(input, charset, extensionRegistry, builder);
@@ -320,14 +321,14 @@ else if (contentType.isCompatibleWith(APPLICATION_XML)) {
320321
this.xmlFormatter.merge(input, charset, extensionRegistry, builder);
321322
}
322323
else {
323-
throw new HttpMessageNotReadableException(
324+
throw new HttpMessageConversionException(
324325
"protobuf-java-format does not support parsing " + contentType);
325326
}
326327
}
327328

328329
@Override
329330
public void print(Message message, OutputStream output, MediaType contentType, Charset charset)
330-
throws IOException, HttpMessageNotWritableException {
331+
throws IOException, HttpMessageConversionException {
331332

332333
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
333334
this.jsonFormatter.print(message, output, charset);
@@ -339,7 +340,7 @@ else if (contentType.isCompatibleWith(TEXT_HTML)) {
339340
this.htmlFormatter.print(message, output, charset);
340341
}
341342
else {
342-
throw new HttpMessageNotWritableException(
343+
throw new HttpMessageConversionException(
343344
"protobuf-java-format does not support printing " + contentType);
344345
}
345346
}
@@ -374,29 +375,29 @@ public boolean supportsWriteOnly(@Nullable MediaType mediaType) {
374375
@Override
375376
public void merge(InputStream input, Charset charset, MediaType contentType,
376377
ExtensionRegistry extensionRegistry, Message.Builder builder)
377-
throws IOException, HttpMessageNotReadableException {
378+
throws IOException, HttpMessageConversionException {
378379

379380
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
380381
InputStreamReader reader = new InputStreamReader(input, charset);
381382
this.parser.merge(reader, builder);
382383
}
383384
else {
384-
throw new HttpMessageNotReadableException(
385+
throw new HttpMessageConversionException(
385386
"protobuf-java-util does not support parsing " + contentType);
386387
}
387388
}
388389

389390
@Override
390391
public void print(Message message, OutputStream output, MediaType contentType, Charset charset)
391-
throws IOException, HttpMessageNotWritableException {
392+
throws IOException, HttpMessageConversionException {
392393

393394
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
394395
OutputStreamWriter writer = new OutputStreamWriter(output, charset);
395396
this.printer.appendTo(message, writer);
396397
writer.flush();
397398
}
398399
else {
399-
throw new HttpMessageNotWritableException(
400+
throw new HttpMessageConversionException(
400401
"protobuf-java-util does not support printing " + contentType);
401402
}
402403
}

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

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.http.HttpOutputMessage;
3030
import org.springframework.http.MediaType;
3131
import org.springframework.http.converter.AbstractHttpMessageConverter;
32+
import org.springframework.http.converter.HttpMessageConversionException;
3233
import org.springframework.http.converter.HttpMessageNotReadableException;
3334
import org.springframework.http.converter.HttpMessageNotWritableException;
3435

@@ -41,6 +42,7 @@
4142
* supportedMediaTypes} property.
4243
*
4344
* @author Arjen Poutsma
45+
* @author Juergen Hoeller
4446
* @since 3.0
4547
* @param <T> the converted object type
4648
*/
@@ -62,14 +64,31 @@ protected AbstractXmlHttpMessageConverter() {
6264
public final T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
6365
throws IOException, HttpMessageNotReadableException {
6466

65-
return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody()));
67+
try {
68+
return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody()));
69+
}
70+
catch (IOException | HttpMessageConversionException ex) {
71+
throw ex;
72+
}
73+
catch (Exception ex) {
74+
throw new HttpMessageNotReadableException("Could not unmarshal to [" + clazz + "]: " + ex.getMessage(),
75+
ex, inputMessage);
76+
}
6677
}
6778

6879
@Override
6980
protected final void writeInternal(T t, HttpOutputMessage outputMessage)
7081
throws IOException, HttpMessageNotWritableException {
7182

72-
writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody()));
83+
try {
84+
writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody()));
85+
}
86+
catch (IOException | HttpMessageConversionException ex) {
87+
throw ex;
88+
}
89+
catch (Exception ex) {
90+
throw new HttpMessageNotWritableException("Could not marshal [" + t + "]: " + ex.getMessage(), ex);
91+
}
7392
}
7493

7594
/**
@@ -89,21 +108,17 @@ protected void transform(Source source, Result result) throws TransformerExcepti
89108
* @param headers the HTTP input headers
90109
* @param source the HTTP input body
91110
* @return the converted object
92-
* @throws IOException in case of I/O errors
93-
* @throws HttpMessageNotReadableException in case of conversion errors
111+
* @throws Exception in case of I/O or conversion errors
94112
*/
95-
protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source)
96-
throws IOException, HttpMessageNotReadableException;
113+
protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws Exception;
97114

98115
/**
99116
* Abstract template method called from {@link #writeInternal(Object, HttpOutputMessage)}.
100117
* @param t the object to write to the output message
101118
* @param headers the HTTP output headers
102119
* @param result the HTTP output body
103-
* @throws IOException in case of I/O errors
104-
* @throws HttpMessageNotWritableException in case of conversion errors
120+
* @throws Exception in case of I/O or conversion errors
105121
*/
106-
protected abstract void writeToResult(T t, HttpHeaders headers, Result result)
107-
throws IOException, HttpMessageNotWritableException;
122+
protected abstract void writeToResult(T t, HttpHeaders headers, Result result) throws Exception;
108123

109124
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ protected boolean supports(Class<?> clazz) {
132132
}
133133

134134
@Override
135-
protected T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws IOException {
135+
protected T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) throws Exception {
136136
// should not be called, since we return false for canRead(Class)
137137
throw new UnsupportedOperationException();
138138
}
@@ -160,18 +160,20 @@ else if (elementClass.isAnnotationPresent(XmlType.class)) {
160160
}
161161
else {
162162
// should not happen, since we check in canRead(Type)
163-
throw new HttpMessageNotReadableException("Cannot unmarshal to [" + elementClass + "]");
163+
throw new HttpMessageNotReadableException(
164+
"Cannot unmarshal to [" + elementClass + "]", inputMessage);
164165
}
165166
event = moveToNextElement(streamReader);
166167
}
167168
return result;
168169
}
169170
catch (XMLStreamException ex) {
170-
throw new HttpMessageNotReadableException("Failed to read XML stream: " + ex.getMessage(), ex);
171+
throw new HttpMessageNotReadableException(
172+
"Failed to read XML stream: " + ex.getMessage(), ex, inputMessage);
171173
}
172174
catch (UnmarshalException ex) {
173175
throw new HttpMessageNotReadableException(
174-
"Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex);
176+
"Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex, inputMessage);
175177
}
176178
catch (JAXBException ex) {
177179
throw new HttpMessageConversionException("Invalid JAXB setup: " + ex.getMessage(), ex);
@@ -237,7 +239,7 @@ public void write(T t, @Nullable Type type, @Nullable MediaType contentType, Htt
237239
}
238240

239241
@Override
240-
protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException {
242+
protected void writeToResult(T t, HttpHeaders headers, Result result) throws Exception {
241243
throw new UnsupportedOperationException();
242244
}
243245

0 commit comments

Comments
 (0)