Refine encoding/decoding exception handling
Starting with removing a package cycle on the use of ResponseStatusException in the codec package, this commit generally refines codec exception handling. The new [Encoding|Decoding]Exception mirror the existing HttpMessageNot[Readable|Writable]Exception and are used similarly especially to differentiate betwen 400 and 500 errors when parsing server request body content. The commit also aligns some of the exception handling of JSON and XML on the WebFlux side with that on the Spring MVC side. Issue: SPR-15516
This commit is contained in:
@@ -21,9 +21,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.codec.InternalCodecException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -88,9 +85,7 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
Map<String, Object> hints) {
|
||||
|
||||
MediaType contentType = getContentType(message);
|
||||
return this.decoder
|
||||
.decode(message.getBody(), elementType, contentType, hints)
|
||||
.onErrorMap(this::mapError);
|
||||
return this.decoder.decode(message.getBody(), elementType, contentType, hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,9 +93,7 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
Map<String, Object> hints) {
|
||||
|
||||
MediaType contentType = getContentType(message);
|
||||
return this.decoder
|
||||
.decodeToMono(message.getBody(), elementType, contentType, hints)
|
||||
.onErrorMap(this::mapError);
|
||||
return this.decoder.decodeToMono(message.getBody(), elementType, contentType, hints);
|
||||
}
|
||||
|
||||
private MediaType getContentType(HttpMessage inputMessage) {
|
||||
@@ -108,16 +101,6 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
return (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
private Throwable mapError(Throwable ex) {
|
||||
if (ex instanceof ResponseStatusException) {
|
||||
return ex;
|
||||
}
|
||||
else if (ex instanceof InternalCodecException) {
|
||||
return new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to decode HTTP message", ex);
|
||||
}
|
||||
return new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to decode HTTP message", ex);
|
||||
}
|
||||
|
||||
|
||||
// Server-side only...
|
||||
|
||||
|
||||
@@ -22,14 +22,13 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
@@ -97,10 +96,9 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
Map<String, Object> hints) {
|
||||
|
||||
MediaType contentType = updateContentType(message, mediaType);
|
||||
DataBufferFactory factory = message.bufferFactory();
|
||||
|
||||
Flux<DataBuffer> body = this.encoder
|
||||
.encode(inputStream, message.bufferFactory(), elementType, contentType, hints)
|
||||
.onErrorMap(this::mapError);
|
||||
Flux<DataBuffer> body = this.encoder.encode(inputStream, factory, elementType, contentType, hints);
|
||||
|
||||
return isStreamingMediaType(contentType) ?
|
||||
message.writeAndFlushWith(body.map(Flux::just)) :
|
||||
@@ -139,13 +137,6 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
.anyMatch(contentType::isCompatibleWith);
|
||||
}
|
||||
|
||||
private Throwable mapError(Throwable ex) {
|
||||
if (ex instanceof ResponseStatusException) {
|
||||
return ex;
|
||||
}
|
||||
return new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to encode HTTP message", ex);
|
||||
}
|
||||
|
||||
|
||||
// Server side only...
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
@@ -32,10 +33,10 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.DecodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.codec.HttpMessageDecoder;
|
||||
import org.springframework.core.codec.InternalCodecException;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
@@ -116,10 +117,13 @@ public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMes
|
||||
return value;
|
||||
}
|
||||
catch (InvalidDefinitionException ex) {
|
||||
throw new InternalCodecException("Error while reading the data", ex);
|
||||
throw new CodecException("Type definition error: " + ex.getMessage(), ex);
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
throw new DecodingException("JSON parse error: " + ex.getMessage(), ex);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new CodecException("Error while reading the data", ex);
|
||||
throw new CodecException("I/O error while reading: " + ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.PrettyPrinter;
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
@@ -39,6 +40,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.EncodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -164,8 +166,11 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes
|
||||
try {
|
||||
writer.writeValue(outputStream, value);
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
throw new EncodingException("JSON encoding error: " + ex.getMessage(), ex);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new CodecException("Error while writing the data", ex);
|
||||
throw new CodecException("I/O error while writing: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
||||
@@ -37,7 +37,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.AbstractDecoder;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.DecodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
@@ -216,7 +216,7 @@ public class Jaxb2XmlDecoder extends AbstractDecoder<Object> {
|
||||
}
|
||||
}
|
||||
catch (JAXBException ex) {
|
||||
throw new CodecException(ex.getMessage(), ex);
|
||||
throw new DecodingException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.UnmarshalException;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@@ -28,6 +29,8 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.AbstractSingleValueEncoder;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.EncodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -73,13 +76,16 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
|
||||
OutputStream outputStream = buffer.asOutputStream();
|
||||
Class<?> clazz = ClassUtils.getUserClass(value);
|
||||
Marshaller marshaller = jaxbContexts.createMarshaller(clazz);
|
||||
marshaller
|
||||
.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
|
||||
marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
|
||||
marshaller.marshal(value, outputStream);
|
||||
return Flux.just(buffer);
|
||||
}
|
||||
catch (UnmarshalException ex) {
|
||||
return Flux.error(new EncodingException(
|
||||
"Could not unmarshal to [" + value.getClass() + "]: " + ex.getMessage(), ex));
|
||||
}
|
||||
catch (JAXBException ex) {
|
||||
return Flux.error(ex);
|
||||
return Flux.error(new CodecException("Could not instantiate JAXBContext: " + ex.getMessage(), ex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user