diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java index 7aae8092886..91507fdb248 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java @@ -25,9 +25,11 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.util.TokenBuffer; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -188,10 +190,18 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple } private CodecException processException(IOException ex) { - if (ex instanceof InvalidDefinitionException) { + if (ex instanceof MismatchedInputException) { // specific kind of JsonMappingException + String originalMessage = ((MismatchedInputException) ex).getOriginalMessage(); + return new DecodingException("Invalid JSON input: " + originalMessage, ex); + } + if (ex instanceof InvalidDefinitionException) { // another kind of JsonMappingException JavaType type = ((InvalidDefinitionException) ex).getType(); return new CodecException("Type definition error: " + type, ex); } + if (ex instanceof JsonMappingException) { // typically ValueInstantiationException + String originalMessage = ((JsonMappingException) ex).getOriginalMessage(); + return new CodecException("JSON conversion problem: " + originalMessage, ex); + } if (ex instanceof JsonProcessingException) { String originalMessage = ((JsonProcessingException) ex).getOriginalMessage(); return new DecodingException("JSON decoding error: " + originalMessage, ex); @@ -200,7 +210,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple } - // HttpMessageDecoder... + // HttpMessageDecoder @Override public Map getDecodeHints(ResolvableType actualType, ResolvableType elementType, @@ -214,7 +224,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple return getMimeTypes(); } - // Jackson2CodecSupport ... + // Jackson2CodecSupport @Override protected A getAnnotation(MethodParameter parameter, Class annotType) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java index b195c9acd61..adccdd80831 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java @@ -30,10 +30,12 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SequenceWriter; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -164,15 +166,20 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple writer.writeValue(generator, value); generator.flush(); } - catch (InvalidDefinitionException ex) { + catch (MismatchedInputException ex) { // specific kind of JsonMappingException + throw new EncodingException("Invalid JSON input: " + ex.getOriginalMessage(), ex); + } + catch (InvalidDefinitionException ex) { // another kind of JsonMappingException throw new CodecException("Type definition error: " + ex.getType(), ex); } + catch (JsonMappingException ex) { // typically ValueInstantiationException + throw new CodecException("JSON conversion problem: " + ex.getOriginalMessage(), ex); + } catch (JsonProcessingException ex) { throw new EncodingException("JSON encoding error: " + ex.getOriginalMessage(), ex); } catch (IOException ex) { - throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", - ex); + throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", ex); } byte[] bytes = byteBuilder.toByteArray(); @@ -198,8 +205,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple throw new EncodingException("JSON encoding error: " + ex.getOriginalMessage(), ex); } catch (IOException ex) { - throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", - ex); + throw new IllegalStateException("Unexpected I/O error while writing to byte array builder", ex); } byte[] bytes = byteArrayBuilder.toByteArray(); @@ -281,7 +287,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple } - // HttpMessageEncoder... + // HttpMessageEncoder @Override public List getEncodableMimeTypes() { @@ -300,7 +306,8 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple return (actualType != null ? getHints(actualType) : Hints.none()); } - // Jackson2CodecSupport ... + + // Jackson2CodecSupport @Override protected A getAnnotation(MethodParameter parameter, Class annotType) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 615f197d3ff..04106d9462b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -36,6 +36,7 @@ import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -238,9 +239,15 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener } return this.objectMapper.readValue(inputMessage.getBody(), javaType); } - catch (InvalidDefinitionException ex) { + catch (MismatchedInputException ex) { // specific kind of JsonMappingException + throw new HttpMessageNotReadableException("Invalid JSON input: " + ex.getOriginalMessage(), ex, inputMessage); + } + catch (InvalidDefinitionException ex) { // another kind of JsonMappingException throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex); } + catch (JsonMappingException ex) { // typically ValueInstantiationException + throw new HttpMessageConversionException("JSON conversion problem: " + ex.getOriginalMessage(), ex); + } catch (JsonProcessingException ex) { throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage); } @@ -289,9 +296,15 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener writeSuffix(generator, object); generator.flush(); } - catch (InvalidDefinitionException ex) { + catch (MismatchedInputException ex) { // specific kind of JsonMappingException + throw new HttpMessageNotWritableException("Invalid JSON input: " + ex.getOriginalMessage(), ex); + } + catch (InvalidDefinitionException ex) { // another kind of JsonMappingException throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex); } + catch (JsonMappingException ex) { // typically ValueInstantiationException + throw new HttpMessageConversionException("JSON mapping problem: " + ex.getPathReference(), ex); + } catch (JsonProcessingException ex) { throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex); }