Browse Source

Fix handling of ServerSentEvent with Jackson encoder

This commit fixes ServerSentEvent handling with Jackson encoder
when no Accept header is specified.

It also moves the String checks to the JSON codec level, as they do not
make sense for binary formats.

Closes gh-35872
pull/35899/head
Sébastien Deleuze 1 month ago
parent
commit
c10266e57e
  1. 9
      spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonDecoder.java
  2. 9
      spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonEncoder.java
  3. 5
      spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonDecoder.java
  4. 5
      spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java
  5. 2
      spring-web/src/test/java/org/springframework/http/codec/cbor/JacksonCborDecoderTests.java
  6. 2
      spring-web/src/test/java/org/springframework/http/codec/cbor/JacksonCborEncoderTests.java
  7. 2
      spring-web/src/test/java/org/springframework/http/codec/smile/JacksonSmileDecoderTests.java
  8. 3
      spring-web/src/test/java/org/springframework/http/codec/smile/JacksonSmileEncoderTests.java
  9. 1
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/SseIntegrationTests.java

9
spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonDecoder.java

@ -102,14 +102,7 @@ public abstract class AbstractJacksonDecoder<T extends ObjectMapper> extends Jac @@ -102,14 +102,7 @@ public abstract class AbstractJacksonDecoder<T extends ObjectMapper> extends Jac
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
if (!supportsMimeType(mimeType)) {
return false;
}
T mapper = selectMapper(elementType, mimeType);
if (mapper == null) {
return false;
}
return !CharSequence.class.isAssignableFrom(elementType.toClass());
return supportsMimeType(mimeType) && (selectMapper(elementType, mimeType) != null);
}
@Override

9
spring-web/src/main/java/org/springframework/http/codec/AbstractJacksonEncoder.java

@ -126,14 +126,11 @@ public abstract class AbstractJacksonEncoder<T extends ObjectMapper> extends Jac @@ -126,14 +126,11 @@ public abstract class AbstractJacksonEncoder<T extends ObjectMapper> extends Jac
if (this.mapperRegistrations != null && selectMapper(elementType, mimeType) == null) {
return false;
}
Class<?> clazz = elementType.resolve();
if (clazz == null) {
return true;
}
if (MappingJacksonValue.class.isAssignableFrom(clazz)) {
Class<?> elementClass = elementType.toClass();
if (MappingJacksonValue.class.isAssignableFrom(elementClass)) {
throw new UnsupportedOperationException("MappingJacksonValue is not supported, use hints instead");
}
return !String.class.isAssignableFrom(clazz);
return !ServerSentEvent.class.isAssignableFrom(elementClass);
}
@Override

5
spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonDecoder.java

@ -104,6 +104,11 @@ public class JacksonJsonDecoder extends AbstractJacksonDecoder<JsonMapper> { @@ -104,6 +104,11 @@ public class JacksonJsonDecoder extends AbstractJacksonDecoder<JsonMapper> {
super(mapper, mimeTypes);
}
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
return super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass());
}
@Override
protected Flux<DataBuffer> processInput(Publisher<DataBuffer> input, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {

5
spring-web/src/main/java/org/springframework/http/codec/json/JacksonJsonEncoder.java

@ -121,6 +121,11 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> { @@ -121,6 +121,11 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
}
@Override
public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
return super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass());
}
@Override
protected List<MimeType> getMediaTypesForProblemDetail() {
return problemDetailMimeTypes;

2
spring-web/src/test/java/org/springframework/http/codec/cbor/JacksonCborDecoderTests.java

@ -57,7 +57,7 @@ class JacksonCborDecoderTests extends AbstractDecoderTests<JacksonCborDecoder> { @@ -57,7 +57,7 @@ class JacksonCborDecoderTests extends AbstractDecoderTests<JacksonCborDecoder> {
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), MediaType.APPLICATION_CBOR)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), null)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse();
}

2
spring-web/src/test/java/org/springframework/http/codec/cbor/JacksonCborEncoderTests.java

@ -59,6 +59,7 @@ class JacksonCborEncoderTests extends AbstractLeakCheckingTests { @@ -59,6 +59,7 @@ class JacksonCborEncoderTests extends AbstractLeakCheckingTests {
ResolvableType pojoType = ResolvableType.forClass(Pojo.class);
assertThat(this.encoder.canEncode(pojoType, MediaType.APPLICATION_CBOR)).isTrue();
assertThat(this.encoder.canEncode(pojoType, null)).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(String.class), null)).isTrue();
// SPR-15464
assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue();
@ -66,7 +67,6 @@ class JacksonCborEncoderTests extends AbstractLeakCheckingTests { @@ -66,7 +67,6 @@ class JacksonCborEncoderTests extends AbstractLeakCheckingTests {
@Test
void canNotEncode() {
assertThat(this.encoder.canEncode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class), APPLICATION_XML)).isFalse();
}

2
spring-web/src/test/java/org/springframework/http/codec/smile/JacksonSmileDecoderTests.java

@ -62,7 +62,7 @@ class JacksonSmileDecoderTests extends AbstractDecoderTests<JacksonSmileDecoder> @@ -62,7 +62,7 @@ class JacksonSmileDecoderTests extends AbstractDecoderTests<JacksonSmileDecoder>
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), STREAM_SMILE_MIME_TYPE)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), null)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse();
}

3
spring-web/src/test/java/org/springframework/http/codec/smile/JacksonSmileEncoderTests.java

@ -65,6 +65,7 @@ class JacksonSmileEncoderTests extends AbstractEncoderTests<JacksonSmileEncoder> @@ -65,6 +65,7 @@ class JacksonSmileEncoderTests extends AbstractEncoderTests<JacksonSmileEncoder>
assertThat(this.encoder.canEncode(pojoType, SMILE_MIME_TYPE)).isTrue();
assertThat(this.encoder.canEncode(pojoType, STREAM_SMILE_MIME_TYPE)).isTrue();
assertThat(this.encoder.canEncode(pojoType, null)).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(String.class), null)).isTrue();
// SPR-15464
assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue();
@ -72,7 +73,7 @@ class JacksonSmileEncoderTests extends AbstractEncoderTests<JacksonSmileEncoder> @@ -72,7 +73,7 @@ class JacksonSmileEncoderTests extends AbstractEncoderTests<JacksonSmileEncoder>
@Test
void cannotEncode() {
assertThat(this.encoder.canEncode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class), APPLICATION_XML)).isFalse();
}

1
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/SseIntegrationTests.java

@ -146,7 +146,6 @@ class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests { @@ -146,7 +146,6 @@ class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
Flux<ServerSentEvent<Person>> result = this.webClient.get()
.uri("/event")
.accept(TEXT_EVENT_STREAM)
.retrieve()
.bodyToFlux(new ParameterizedTypeReference<>() {});

Loading…
Cancel
Save