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 4ef9b902def..595e70a3236 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-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -471,7 +472,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener if (filters != null) { objectWriter = objectWriter.with(filters); } - if (javaType != null && javaType.isContainerType()) { + if (javaType != null && (javaType.isContainerType() || javaType.isTypeOrSubTypeOf(Optional.class))) { objectWriter = objectWriter.forType(javaType); } SerializationConfig config = objectWriter.getConfig(); diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java index b5a24d34543..24f933208dc 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -24,8 +24,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; @@ -345,6 +348,18 @@ public class MappingJackson2HttpMessageConverterTests { JSONAssert.assertEquals(body, outputMessage.getBodyAsString(StandardCharsets.UTF_8), true); } + // gh-24498 + @Test + public void writeOptional() throws IOException { + ParameterizedTypeReference> optionalParent = new ParameterizedTypeReference<>() {}; + Optional result = Optional.of(new Impl1()); + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); + converter.write(result, optionalParent.getType(), MediaType.APPLICATION_JSON, outputMessage); + + assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8)) + .contains("@type"); + } + @Test public void prettyPrint() throws Exception { MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); @@ -773,6 +788,18 @@ public class MappingJackson2HttpMessageConverterTests { } } + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME) + @JsonSubTypes(value = {@JsonSubTypes.Type(value = Impl1.class), + @JsonSubTypes.Type(value = Impl2.class)}) + public static interface MyParent { + } + + public static class Impl1 implements MyParent { + } + + public static class Impl2 implements MyParent { + } + private static class MappingJackson2HttpMessageConverterWithCustomization extends MappingJackson2HttpMessageConverter { @Override