diff --git a/module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfiguration.java b/module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfiguration.java index 276c3eaff099..ec4e04be5858 100644 --- a/module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfiguration.java +++ b/module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.jackson; +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.JsonInclude.Include; import tools.jackson.databind.json.JsonMapper; @@ -42,6 +43,7 @@ EndpointJsonMapper endpointJsonMapper() { JsonMapper jsonMapper = JsonMapper.builder() .changeDefaultPropertyInclusion( (value) -> value.withValueInclusion(Include.NON_NULL).withContentInclusion(Include.NON_NULL)) + .changeDefaultVisibility((vc) -> vc.withCreatorVisibility(Visibility.NON_PRIVATE)) .build(); return () -> jsonMapper; } diff --git a/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfigurationTests.java b/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfigurationTests.java index 6e8ad5a0d775..173a8b00d3e8 100644 --- a/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfigurationTests.java +++ b/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfigurationTests.java @@ -25,7 +25,10 @@ import org.junit.jupiter.api.Test; import tools.jackson.databind.json.JsonMapper; +import org.springframework.boot.actuate.autoconfigure.endpoint.jackson.example.SomeResponseBody; +import org.springframework.boot.actuate.endpoint.OperationResponseBody; import org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper; +import org.springframework.boot.actuate.web.mappings.MappingsEndpoint.ApplicationMappingsDescriptor; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -91,6 +94,23 @@ void endpointJsonMapperDoesNotSerializeNullValues() { }); } + @Test + void endpointShouldDeserializeOperationResponseBodies() { + this.runner.run((context) -> { + JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get(); + String json = """ + { + "value1": "a", + "value2": "b", + } + """; + SomeResponseBody responseBody = jsonMapper.readValue(json, SomeResponseBody.class); + assertThat(responseBody.getValue1()).isEqualTo("a"); + assertThat(responseBody.getValue2()).isEqualTo("b"); + }); + + } + @Configuration(proxyBeanMethods = false) static class TestEndpointMapperConfiguration { diff --git a/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/example/SomeResponseBody.java b/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/example/SomeResponseBody.java new file mode 100644 index 000000000000..9347a81c2c72 --- /dev/null +++ b/module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/example/SomeResponseBody.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.endpoint.jackson.example; + +import org.springframework.boot.actuate.endpoint.OperationResponseBody; + +/** + * A class that reassembles something like + * {@code org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint.MetricDescriptor}, + * not exposing a public constructor, only package level. They could be deserialized with + * Jackson 2 out of the box, but not with Jackson 3 anymore. Constructors with one + * argument still deserialize as is, so this need to have two or more. + * + * @author Michael J. Simons + */ +public final class SomeResponseBody implements OperationResponseBody { + + private final String value1; + + private final String value2; + + SomeResponseBody(String value1, String value2) { + this.value1 = value1; + this.value2 = value2; + } + + public String getValue1() { + return this.value1; + } + + public String getValue2() { + return this.value2; + } + +}