From 53fe4be3a5a9838362debf2cb76ac61d7510ba36 Mon Sep 17 00:00:00 2001 From: Greg Felix Date: Wed, 9 Sep 2026 13:48:07 -0600 Subject: [PATCH] fix(mdx-web): retain Jackson JSON converter for actuator serialization MdxOnDemandSerializationWebMvcConfigurer strips every message converter not in its allowlist. Under Spring Boot 4 the actuator health endpoint returns SystemHealthDescriptor, which is serialized with Jackson; with the Jackson JSON converter removed there is no writable converter for it, so /actuator/health fails with HttpMessageNotWritableException ("No converter for [SystemHealthDescriptor] with preset Content-Type 'null'") and Kubernetes health probes never pass. Add JacksonJsonHttpMessageConverter to the allowlist so actuator (and any non-MDX JSON) endpoints can serialize, while MDX endpoints continue to use Gson. --- .../mdx/web/MdxOnDemandSerializationWebMvcConfigurer.java | 7 ++++++- .../MdxOnDemandSerializationWebMvcConfigurerTest.groovy | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mdx-web/src/main/java/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurer.java b/mdx-web/src/main/java/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurer.java index 75ca5475..87b53636 100644 --- a/mdx-web/src/main/java/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurer.java +++ b/mdx-web/src/main/java/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurer.java @@ -11,6 +11,7 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -22,7 +23,10 @@ public class MdxOnDemandSerializationWebMvcConfigurer implements WebMvcConfigurer { /** - * List of all configured converts. All others will be removed before inserting custom MappingJackson2XmlHttpMessageConverter + * Converters retained by {@link #extendMessageConverters(List)}; every other converter is removed before the + * custom XML converter is appended. Gson handles MDX JSON serialization. The Jackson JSON converter is retained + * because Spring Boot's actuator endpoints (e.g. {@code /actuator/health}) are serialized with Jackson; without it + * those responses have no writable converter and fail with {@code HttpMessageNotWritableException}. */ static final List> CONVERT_CLASSES; static { @@ -30,6 +34,7 @@ public class MdxOnDemandSerializationWebMvcConfigurer implements WebMvcConfigure CONVERT_CLASSES.add(GsonHttpMessageConverter.class); CONVERT_CLASSES.add(StringHttpMessageConverter.class); CONVERT_CLASSES.add(ByteArrayHttpMessageConverter.class); + CONVERT_CLASSES.add(JacksonJsonHttpMessageConverter.class); } @Override diff --git a/mdx-web/src/test/groovy/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurerTest.groovy b/mdx-web/src/test/groovy/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurerTest.groovy index 25c18327..944467f9 100644 --- a/mdx-web/src/test/groovy/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurerTest.groovy +++ b/mdx-web/src/test/groovy/com/mx/path/model/mdx/web/MdxOnDemandSerializationWebMvcConfigurerTest.groovy @@ -5,6 +5,7 @@ import org.springframework.http.converter.FormHttpMessageConverter import org.springframework.http.converter.ResourceHttpMessageConverter import org.springframework.http.converter.StringHttpMessageConverter import org.springframework.http.converter.json.GsonHttpMessageConverter +import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter import spock.lang.Specification @@ -22,6 +23,7 @@ class MdxOnDemandSerializationWebMvcConfigurerTest extends Specification { def "filters non-whitelisted message converters and appends the custom XML converter"() { given: def gsonConverter = new GsonHttpMessageConverter() + def jacksonJsonConverter = new JacksonJsonHttpMessageConverter() def stringConverter = new StringHttpMessageConverter() def byteArrayConverter = new ByteArrayHttpMessageConverter() def unwantedResourceConverter = new ResourceHttpMessageConverter() @@ -30,6 +32,7 @@ class MdxOnDemandSerializationWebMvcConfigurerTest extends Specification { def converters = [ unwantedResourceConverter, gsonConverter, + jacksonJsonConverter, unwantedFormConverter, stringConverter, byteArrayConverter @@ -40,8 +43,9 @@ class MdxOnDemandSerializationWebMvcConfigurerTest extends Specification { then: verifyAll(converters) { - it.size() == 4 + it.size() == 5 it.contains(gsonConverter) + it.contains(jacksonJsonConverter) it.contains(stringConverter) it.contains(byteArrayConverter) !it.contains(unwantedResourceConverter)