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.