When using a custom object mapper with MapperFeature.AUTO_DETECT_GETTERS
disabled the detailed information for Health endpoint is not returned.
The status is returned as expected but not the detailed information.
From the code the getStatus
method has Jackson annotation but the getDetails
is lacking annotation.
Problem found using SpringBoot spring-boot-starter-parent version 2.0.1.RELEASE.
As a workaround and for verification of the problem is related to Jackson an MixIn class where created annotation for getStatus and getDetails and after that the information where displayed as expected.
mapper.addMixIn(Health.class, HealthMixIn.class);
public abstract class HealthMixIn {
@JsonValue public abstract Object getStatus();
@JsonValue public abstract Object getDetails();
}
How to repeat:
@Bean
@Primary
public ObjectMapper create() {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.AUTO_DETECT_GETTERS)
return mapper;
}
Comment From: philwebb
I wonder if we should create our own ObjectMapper
for the actuator.
Comment From: snicoll
If we do, I am expecting some stuff to be configurable. For instance, you may want that Instant
are formatted consistently and having our own means you'd need to configure things in two places. Doing this will certainly break other use cases.
Comment From: wilkinsona
For instance, you may want that Instant are formatted consistently
We document the actuator's format for Instant
so I think this is actually an argument in favour of using our own ObjectMapper
. Doing so would mean that the precise format of the responses will always match what we've documented.
Doing this will certainly break other use cases
On the other hand, I agree with this. While it may be a bad thing that configuring the global ObjectMapper
affects the Actuator's response format, the reality is that it does. I would be surprised if at least some users aren't currently relying on that.
Comment From: snicoll
We document the actuator's format for Instant
I am not surprised but for some reason I completely eluded that. I think it's going to be quite hard to do this right. Users may care about a single ObjectMapper
so we should give them the ability to do that. And the auto-configured ObjectMapper
is already @Primary
so we'd probably need some way to qualify the actuator specific one, if any.
Comment From: wilkinsona
If we add an Actuator-specific ObjectMapper
, we'll perhaps be adding to the problem that's described in https://github.com/spring-projects/spring-boot/issues/1789.
Comment From: vilhelm-persson-viper
Referring to initial title where the problem where detected.
For the Health actuator I think that adding Jackson annotation also for the getDetails
method would solve the problem with most custom configuration on the ObjectMapper
.
Comment From: joshiste
Currently the easiest way to reconfigure the global ObjectMapper without having the actuator endpoints affected is this:
@Bean
public MappingJackson2HttpMessageConverter actuatorHttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder.json().featuresToDisable(WRITE_DATES_AS_TIMESTAMPS).build());
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.parseMediaType(ActuatorMediaType.V2_JSON)));
return converter;
}
I'd really like to submit a PR for spring boot that takes this approach, as it would make the actuators' format "stable" (useful for spring boot admin users). The downside (as mentioned before): you can't customize this mapper... (unless the user overrides the actuatorHttpMessageConverter)
WDYT @wilkinsona @snicoll, is such a PR worth it?
Comment From: wilkinsona
Interesting approach, @joshiste. Unfortunately, there's a bit more to it I think as the Actuator also uses an ObjectMapper
in various other places (the env and config props endpoints, JMX endpoints, etc) and we don't want to contribute to the problem that #1789 is tracking without exhausting other possibilities first.
In short, I don't think such a PR is worth it right now. We may end up taking an approach like the one you have proposed, but I think some investigation and experimentation is needed first.
Comment From: joshiste
@philwebb you added the status: blocked
label. I'd be interested in some background info on that and the progress on this topic.
Comment From: philwebb
I added blocked because it feels like we really need to solve ~~#1789~~ [edit: I meant #13766] before this one. There's not really been much progress on that one unfortunately.
Comment From: snicoll
@philwebb wrong issue? #1789 is closed.
Comment From: philwebb
Hmm, I can't remember why I marked it blocked then 🤷♂️
Comment From: vilhelm-persson-viper
Hi. As a comment this issue from the beginning where named "Health detail information need ObjectMapper auto detect getter". For the Health actuator one of the fileds is already annotated with @JsonProperty("status"). So for the Health actuator one possible solution is to annotate alos the rest of the expected response. And then it can handle any settings done for the default object mapper. If possible this pattern might also be applicable for rest of the actuators and stating that expected output should be annotated? (I dont know how many actuators that are dependent on object mapper settings for date format and other configurable options)
Comment From: bclozel
@philwebb Maybe #13766 ?
Comment From: abccbaandy
I think we really need resolve this issue.
I want serialize all number as string, I can just use one line code if we separate actuator objectmapper and spring web objectmapper.
spring.jackson.generator.write-numbers-as-strings=true
Comment From: irobertson
Absent a separate ObjectMapper, would the team be willing to consider adding Jackson annotations to the individual actuator result classes, so that a spring boot app with an ObjectMapper with reduced visibility settings can still use the actuator, without resorting to using mixins?
Comment From: philwebb
@irobertson That might be the most pragmatic solution for now. I'll flag this one for discussion again but we won't get to talk about it for a few weeks because most of the team are away.
Comment From: wilkinsona
Let's start exploring this for 2.3.0.M2.
Comment From: bclozel
I've just closed this issue, opting for an Actuator-specific ObjectMapper
instance. This instance is used for Spring MVC, Spring WebFlux, JMX and Jersey - Actuator endpoints.
The JSON mapper becomes now an implementation detail of Actuator. Jackson was already a hard dependency, but this time the mapper is totally independent from the rest of the application.
This has the following advantages:
* changing the application JSON serialization configuration won't have any effect on Actuator JSON responses (= they'll be consistent across applications)
* in the future, Spring Boot might choose another JSON mapper or different defaults for that without any effect on the application itself (see #13766)
* we don't need to annotate classes to ensure that the response format will be consistent
* using the Gson mapper in the application (i.e. adding the library as a dependency and using "spring.mvc.converters.preferred-json-mapper:gson"
) now works. It was previously failing on the /actuator/beans
endpoint
There are some downsides to that approach.
First, we're making #1789 worse because we now have 3 ObjectMapper
instances in a typical web application with Actuator: one for the application, one for Actuator endpoints, and another one specifically for the config properties endpoint (as we have very specific constraints for serializing those).
Also, this ObjectMapper
instance only comes into play when the Actuator-specific media types are used (such as "application/vnd.spring-boot.actuator.v3+json"
). If the client explicitly asks for "application/json"
, the application's ObjectMapper
might be used in this case and the proper serialization is not guaranteed anymore.
Comment From: bclozel
We need to revert that change because of #20211.
With the current Actuator setup, a custom annotation-based HandlerMapping
instance for Actuator endpoints will still share the RequestMappingHandlerAdapter
infrastructure with the main application. In the case of #20211, we can't really have actuator-specific HTTP message converters, as we would need to only involve them for some endpoints.
Instead, we should consider whether we can implement the MVC web adapter layer for Actuator using Servlet Functional Endpoints, see #20290. In that mode, the message converters would be limited to that specific HandlerMapping
implementation. Right now, adding another message converter to the list has side-effects on the main application and this is not acceptable.
Comment From: bclozel
Actually, closing in favor of #20291 as we need to keep this issue tied to the released 2.3.0.M2 version.