Handle Jackson InvalidDefinitionException with 5xx status in WebFlux

Issue: SPR-14925
This commit is contained in:
Sebastien Deleuze
2017-04-11 11:46:49 +02:00
parent c4e0d6c2a2
commit 23e35c0e1a
5 changed files with 95 additions and 6 deletions

View File

@@ -21,7 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.codec.CodecException;
import org.springframework.core.codec.InternalCodecException;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Flux;
@@ -112,10 +112,10 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
if (ex instanceof ResponseStatusException) {
return ex;
}
else if (ex instanceof CodecException) {
return new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to decode HTTP message", ex);
else if (ex instanceof InternalCodecException) {
return new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to decode HTTP message", ex);
}
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);
}

View File

@@ -24,6 +24,7 @@ import java.util.Map;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -34,6 +35,7 @@ import org.springframework.core.codec.CodecException;
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;
@@ -113,6 +115,9 @@ public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMes
DataBufferUtils.release(dataBuffer);
return value;
}
catch (InvalidDefinitionException ex) {
throw new InternalCodecException("Error while reading the data", ex);
}
catch (IOException ex) {
throw new CodecException("Error while reading the data", ex);
}

View File

@@ -33,6 +33,7 @@ import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.CodecException;
import org.springframework.core.codec.InternalCodecException;
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.Pojo;
@@ -160,4 +161,44 @@ public class Jackson2JsonDecoderTests extends AbstractDataBufferAllocatingTestCa
.verifyComplete();
}
@Test
public void invalidData() throws Exception {
Flux<DataBuffer> source = Flux.just(stringBuffer( "{\"property1\":\"foo\""));
ResolvableType elementType = forClass(BeanWithNoDefaultConstructor.class);
Flux<Object> flux = new Jackson2JsonDecoder().decode(source, elementType, null, emptyMap());
StepVerifier.create(flux).expectError(InternalCodecException.class);
}
@Test
public void noDefaultConstructor() throws Exception {
Flux<DataBuffer> source = Flux.just(stringBuffer( "{\"property1\":\"foo\",\"property2\":\"bar\"}"));
ResolvableType elementType = forClass(BeanWithNoDefaultConstructor.class);
Flux<Object> flux = new Jackson2JsonDecoder().decode(source, elementType, null, emptyMap());
StepVerifier
.create(flux)
.verifyErrorMatches(ex -> ex instanceof CodecException && !(ex instanceof InternalCodecException));
}
private static class BeanWithNoDefaultConstructor {
private final String property1;
private final String property2;
public BeanWithNoDefaultConstructor(String property1, String property2) {
this.property1 = property1;
this.property2 = property2;
}
public String getProperty1() {
return property1;
}
public String getProperty2() {
return property2;
}
}
}