I have a demo project using Spring Boot 2.7.3. The only dependencies are the web and actuator starters. I try to start the application with a BufferingApplicationStartup and set management.endpoints.web.exposure.include=* in application.properties. This goes well and I can access startup metrics at /actuator/startup.
However, if I add the property spring.jackson.visibility.field=any to application.properties and hit the actuator/startup endpoint I get the following error:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.Clock$SystemClock` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: org.springframework.boot.actuate.startup.StartupEndpoint$StartupResponse["timeline"]
->org.springframework.boot.context.metrics.buffering.StartupTimeline["events"]
->java.util.Collections$UnmodifiableRandomAccessList[0]
->org.springframework.boot.context.metrics.buffering.StartupTimeline$TimelineEvent["step"]
->org.springframework.boot.context.metrics.buffering.BufferedStartupStep["recorder"]
->org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup$$Lambda$62/0x0000000800c384d8["arg$1"]
->org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup["clock"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300) ~[jackson-databind-2.13.3.jar:2.13.3]
...
None of the other spring.jackson properties I tried caused this error. Is there perhaps an issue with the ObjectMapper initialization for the startup actuator?
Comment From: philwebb
This is somewhat related to #20291. I'm a little surprised that the same error isn't thrown during regular startup since java.time types are exposed in the getters as well.
@iaptekar Do you have the jackson-datatype-jsr310 library on your classpath? If you're using spring-boot-starter-json or spring-boot-starter-web then it should be pulled in. If not, have you tried adding it to see if it solves the issue?
Comment From: iaptekar
Yes I have jsr310 on the classpath. I am using it via spring-boot-starter-web. Though I have tried adding it as an extra dependency and even had a go at configuring the object mapper in a @Configuration. Nothing changes, as you soon as you add the Visibility.Any option you get that exception.
Comment From: wilkinsona
Jackson's message is misleading. It suggests adding jackson-datatype-jsr310 for any java.time.* type, but jackson-datatype-jsr310 doesn't support serialisation of java.time.Clock$SystemClock. @iaptekar, you may want to raise a Jackson issue for this.
We could address this without tackling #20291 by mapping the StartupTimeline to a DTO where we could have complete control over the classes and their suitability for serialising to JSON. Arguably, this would make the startup endpoint more consistent with other endpoints such as the mappings endpoint and its various descriptors. It would, however, require a breaking change to org.springframework.boot.actuate.startup.StartupEndpoint.StartupResponse which is public API.
Comment From: wilkinsona
We might be able to use @JsonSerialize to take control of how StartupResponse is serialized and avoid the unwanted field serialization.
Comment From: philwebb
I have a branch at https://github.com/philwebb/spring-boot/tree/gh-32297 that shows how @JsonSerialize could work. I'm not totally sure if we should take this approach or not.
Comment From: wilkinsona
I like the approach. It seems low risk and addresses the problem without making a breaking change to public API. One for 3.1.12?
Comment From: jsantana3c
Sorry guys If I probably go off topic in this thread, but using as a reference the https://github.com/spring-projects/spring-boot/issues/20291 and also the field visibility, the isolation isn't behaving probably properly? if you customize the Jackson2ObjectMapperBuilderCustomizer, for example:
public Jackson2ObjectMapperBuilderCustomizer jacksonMapperBuilderCustomizer() {
return builder -> builder
.defaultTyping(ObjectMapper
.DefaultTypeResolverBuilder
.construct(ObjectMapper.DefaultTyping.NON_FINAL, LaissezFaireSubTypeValidator.instance)
.init(JsonTypeInfo.Id.CLASS, null)
.inclusion(JsonTypeInfo.As.PROPERTY));
}
it will add the "_class" the json output of the /actuator endpoints, and for example it breaks "Intellij Actuator tab support", but the main issue is that shouldn't that be isolated?
Thanks
Comment From: wilkinsona
It's hard to say without some more context. If you believe you've found a bug related to Actuator's isolated object mapper, please open a new issue with a minimal sample that reproduces the problem and we can take a look.
Comment From: joaquinjsb
thanks! I'll create a new issue, I thought it was probably related to this.
Comment From: wilkinsona
The last few comments have reminded me that, as of 3.0, this is only a problem when both spring.jackson.visibility.field=any and management.endpoints.jackson.isolated-object-mapper=false are configured. As such, I'm not sure that we should do anything and I'm in favour of closing this one as superseded by https://github.com/spring-projects/spring-boot/issues/20291.
Comment From: joaquinjsb
that could be the same issue I'm being affected, because I have the default management.endpoints.jackson.isolated-object-mapper which is true, and by overriding it to true or leaving default, the changes I do to my Jackson2ObjectMapperBuilderCustomizer is being passed to the objectmapper on the actuator side., do you still think I should open another issue?
Comment From: wilkinsona
Yes please, @joaquinjsb. It's better to keep things separate to begin with and to combine them if necessary than to start trying to track two potentially different problems in the same issue.
Comment From: mhalbritter
and I'm in favour of closing this one
I agree.