Skip to content

fix(mdx-web): restore default message converters - #383

Open
stevecl5 wants to merge 1 commit into
masterfrom
scl/restore-default-message-converters
Open

fix(mdx-web): restore default message converters#383
stevecl5 wants to merge 1 commit into
masterfrom
scl/restore-default-message-converters

Conversation

@stevecl5

@stevecl5 stevecl5 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary of Changes

Resolves an issue introduced during the Spring Boot 4 upgrade where default HTTP message converters (like ByteArrayHttpMessageConverter and StringHttpMessageConverter) were dropped, causing endpoints like /actuator/prometheus to return a 500 Internal Server Error.

Root Cause:
In Spring Boot 4, overriding configureMessageConverters signals to the framework that the application is taking complete manual control of serialization which causes Spring to discard all of its default converters. A new GsonHttpMessageConverter was added back in MdxSerializationConfiguration to fix JSON serialization, but endpoints that return other media types (such as text/plain) were missing the necessary converters to render a response.

The Fix:

  • Migrated MdxOnDemandSerializationWebMvcConfigurer to use extendMessageConverters instead of configureMessageConverters. This allows Spring Boot to safely populate its default converters first, which we then filter to our strict whitelist.
  • Cleaned up MdxSerializationConfiguration by removing the WebMvcConfigurer implementation. Spring Boot will automatically detect our custom @Bean Gson gson() and natively bind it to its own default Gson converter under the hood.

Fixes # https://mxcom.atlassian.net/browse/MC-15146

Public API Additions/Changes

N/A

Downstream Consumer Impact

  • Spring Boot services utilizing this library will regain access to standard default converters.
  • Spring Boot services will be able to query prometheus metrics without getting an error, as long as the endpoint is enabled in the Spring configuration ( application.yml or application.properties ).
  • No breaking changes to existing JSON or XML serialization.

How Has This Been Tested?

I pulled a snapshot version of these changes into path-connector-hancock-whitney and verified the /actuator/prometheus endpoint is working as expected.

Prometheus Response
% curl -s http://localhost:13024/actuator/prometheus 
# HELP application_ready_time_seconds Time taken for the application to be ready to service requests
# TYPE application_ready_time_seconds gauge
application_ready_time_seconds{application="path-connector-hancock-whitney",main_application_class="hancockwhitney.HancockWhitneyApplication"} 226.071
# HELP application_started_time_seconds Time taken to start the application
# TYPE application_started_time_seconds gauge
application_started_time_seconds{application="path-connector-hancock-whitney",main_application_class="hancockwhitney.HancockWhitneyApplication"} 226.053
# HELP disk_free_bytes Usable space for path
# TYPE disk_free_bytes gauge
disk_free_bytes{application="path-connector-hancock-whitney",path="/Users/steven.leighton/dev/path-connector-hancock-whitney/."} 6.2999728128E10
# HELP disk_total_bytes Total space for path
# TYPE disk_total_bytes gauge
disk_total_bytes{application="path-connector-hancock-whitney",path="/Users/steven.leighton/dev/path-connector-hancock-whitney/."} 4.94384795648E11
# HELP executor_active_threads The approximate number of threads that are actively executing tasks
# TYPE executor_active_threads gauge
executor_active_threads{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 0.0
# HELP executor_completed_tasks_total The approximate total number of tasks that have completed execution
# TYPE executor_completed_tasks_total counter
executor_completed_tasks_total{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 0.0
# HELP executor_pool_core_threads The core number of threads for the pool
# TYPE executor_pool_core_threads gauge
executor_pool_core_threads{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 8.0
# HELP executor_pool_max_threads The maximum allowed number of threads in the pool
# TYPE executor_pool_max_threads gauge
executor_pool_max_threads{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 2.147483647E9
# HELP executor_pool_size_threads The current number of threads in the pool
# TYPE executor_pool_size_threads gauge
executor_pool_size_threads{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 0.0
# HELP executor_queue_remaining_tasks The number of additional elements that this queue can ideally accept without blocking
# TYPE executor_queue_remaining_tasks gauge
executor_queue_remaining_tasks{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 2.147483647E9
# HELP executor_queued_tasks The approximate number of tasks that are queued for execution
# TYPE executor_queued_tasks gauge
executor_queued_tasks{application="path-connector-hancock-whitney",name="applicationTaskExecutor"} 0.0
# HELP http_server_requests_active_seconds  
# TYPE http_server_requests_active_seconds summary
http_server_requests_active_seconds_count{application="path-connector-hancock-whitney",exception="none",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN"} 1
http_server_requests_active_seconds_sum{application="path-connector-hancock-whitney",exception="none",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN"} 0.002270292
# HELP http_server_requests_active_seconds_max  
# TYPE http_server_requests_active_seconds_max gauge
http_server_requests_active_seconds_max{application="path-connector-hancock-whitney",exception="none",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN"} 0.002277709
# HELP http_server_requests_seconds  
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="CLIENT_ERROR",status="404",uri="/**"} 1
http_server_requests_seconds_sum{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="CLIENT_ERROR",status="404",uri="/**"} 0.018238
http_server_requests_seconds_count{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/actuator/prometheus"} 2
http_server_requests_seconds_sum{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/actuator/prometheus"} 0.2791595
# HELP http_server_requests_seconds_max  
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="CLIENT_ERROR",status="404",uri="/**"} 0.018238
http_server_requests_seconds_max{application="path-connector-hancock-whitney",error="none",exception="none",method="GET",outcome="SUCCESS",status="200",uri="/actuator/prometheus"} 0.218872375
# HELP jvm_info JVM version info
# TYPE jvm_info gauge
jvm_info{application="path-connector-hancock-whitney",runtime="OpenJDK Runtime Environment",vendor="Eclipse Adoptium",version="21.0.10+7-LTS"} 1
# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool
# TYPE jvm_buffer_count_buffers gauge
jvm_buffer_count_buffers{application="path-connector-hancock-whitney",id="direct"} 10.0
jvm_buffer_count_buffers{application="path-connector-hancock-whitney",id="mapped"} 0.0
jvm_buffer_count_buffers{application="path-connector-hancock-whitney",id="mapped - 'non-volatile memory'"} 0.0
# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{application="path-connector-hancock-whitney",id="direct"} 81920.0
jvm_buffer_memory_used_bytes{application="path-connector-hancock-whitney",id="mapped"} 0.0
jvm_buffer_memory_used_bytes{application="path-connector-hancock-whitney",id="mapped - 'non-volatile memory'"} 0.0
# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool
# TYPE jvm_buffer_total_capacity_bytes gauge
jvm_buffer_total_capacity_bytes{application="path-connector-hancock-whitney",id="direct"} 81920.0
jvm_buffer_total_capacity_bytes{application="path-connector-hancock-whitney",id="mapped"} 0.0
jvm_buffer_total_capacity_bytes{application="path-connector-hancock-whitney",id="mapped - 'non-volatile memory'"} 0.0
# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine
# TYPE jvm_classes_loaded_classes gauge
jvm_classes_loaded_classes{application="path-connector-hancock-whitney"} 14007.0
# HELP jvm_classes_loaded_count_classes_total The number of classes loaded in the Java virtual machine
# TYPE jvm_classes_loaded_count_classes_total counter
jvm_classes_loaded_count_classes_total{application="path-connector-hancock-whitney"} 14007.0
# HELP jvm_classes_unloaded_classes_total The number of classes unloaded in the Java virtual machine
# TYPE jvm_classes_unloaded_classes_total counter
jvm_classes_unloaded_classes_total{application="path-connector-hancock-whitney"} 0.0
# HELP jvm_compilation_time_ms_total The approximate accumulated elapsed time spent in compilation
# TYPE jvm_compilation_time_ms_total counter
jvm_compilation_time_ms_total{application="path-connector-hancock-whitney",compiler="HotSpot 64-Bit Tiered Compilers"} 2013.0
# HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation
# TYPE jvm_gc_live_data_size_bytes gauge
jvm_gc_live_data_size_bytes{application="path-connector-hancock-whitney"} 0.0
# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool
# TYPE jvm_gc_max_data_size_bytes gauge
jvm_gc_max_data_size_bytes{application="path-connector-hancock-whitney"} 8.589934592E9
# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next
# TYPE jvm_gc_memory_allocated_bytes_total counter
jvm_gc_memory_allocated_bytes_total{application="path-connector-hancock-whitney"} 7.5497472E7
# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC
# TYPE jvm_gc_memory_promoted_bytes_total counter
jvm_gc_memory_promoted_bytes_total{application="path-connector-hancock-whitney"} 775248.0
# HELP jvm_gc_overhead An approximation of the percent of CPU time used by GC activities over the last lookback period or since monitoring began, whichever is shorter, in the range [0..1]
# TYPE jvm_gc_overhead gauge
jvm_gc_overhead{application="path-connector-hancock-whitney"} 1.889260178899562E-4
# HELP jvm_gc_pause_seconds Time spent in GC pause
# TYPE jvm_gc_pause_seconds summary
jvm_gc_pause_seconds_count{action="end of minor GC",application="path-connector-hancock-whitney",cause="G1 Evacuation Pause",gc="G1 Young Generation"} 1
jvm_gc_pause_seconds_sum{action="end of minor GC",application="path-connector-hancock-whitney",cause="G1 Evacuation Pause",gc="G1 Young Generation"} 0.012
# HELP jvm_gc_pause_seconds_max Time spent in GC pause
# TYPE jvm_gc_pause_seconds_max gauge
jvm_gc_pause_seconds_max{action="end of minor GC",application="path-connector-hancock-whitney",cause="G1 Evacuation Pause",gc="G1 Young Generation"} 0.012
# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use
# TYPE jvm_memory_committed_bytes gauge
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Eden Space"} 7.5497472E7
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Old Gen"} 5.4525952E7
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Survivor Space"} 1.2582912E7
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="nonheap",id="CodeCache"} 1.5138816E7
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Compressed Class Space"} 9961472.0
jvm_memory_committed_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Metaspace"} 7.5235328E7
# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Eden Space"} -1.0
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Old Gen"} 8.589934592E9
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Survivor Space"} -1.0
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="nonheap",id="CodeCache"} 5.0331648E7
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Compressed Class Space"} 1.073741824E9
jvm_memory_max_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Metaspace"} -1.0
# HELP jvm_memory_usage_after_gc The percentage of long-lived heap pool used after the last GC event, in the range [0..1]
# TYPE jvm_memory_usage_after_gc gauge
jvm_memory_usage_after_gc{application="path-connector-hancock-whitney",area="heap",pool="long-lived"} 0.004819517955183983
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Eden Space"} 2.9360128E7
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Old Gen"} 4.1399344E7
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="heap",id="G1 Survivor Space"} 8581280.0
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="nonheap",id="CodeCache"} 1.5068928E7
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Compressed Class Space"} 9554552.0
jvm_memory_used_bytes{application="path-connector-hancock-whitney",area="nonheap",id="Metaspace"} 7.4285688E7
# HELP jvm_threads_daemon_threads The current number of live daemon threads
# TYPE jvm_threads_daemon_threads gauge
jvm_threads_daemon_threads{application="path-connector-hancock-whitney"} 28.0
# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads
# TYPE jvm_threads_live_threads gauge
jvm_threads_live_threads{application="path-connector-hancock-whitney"} 32.0
# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset
# TYPE jvm_threads_peak_threads gauge
jvm_threads_peak_threads{application="path-connector-hancock-whitney"} 36.0
# HELP jvm_threads_started_threads_total The total number of application threads started in the JVM
# TYPE jvm_threads_started_threads_total counter
jvm_threads_started_threads_total{application="path-connector-hancock-whitney"} 67.0
# HELP jvm_threads_states_threads The current number of threads
# TYPE jvm_threads_states_threads gauge
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="blocked"} 0.0
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="new"} 0.0
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="runnable"} 9.0
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="terminated"} 0.0
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="timed-waiting"} 11.0
jvm_threads_states_threads{application="path-connector-hancock-whitney",state="waiting"} 12.0
# HELP logback_events_total Number of log events that were enabled by the effective log level
# TYPE logback_events_total counter
logback_events_total{application="path-connector-hancock-whitney",level="debug"} 0.0
logback_events_total{application="path-connector-hancock-whitney",level="error"} 0.0
logback_events_total{application="path-connector-hancock-whitney",level="info"} 9.0
logback_events_total{application="path-connector-hancock-whitney",level="trace"} 0.0
logback_events_total{application="path-connector-hancock-whitney",level="warn"} 0.0
# HELP process_cpu_time_ns_total The "cpu time" used by the Java Virtual Machine process
# TYPE process_cpu_time_ns_total counter
process_cpu_time_ns_total{application="path-connector-hancock-whitney"} 2.24719E10
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage{application="path-connector-hancock-whitney"} 0.0064926474464930386
# HELP process_files_max_files The maximum file descriptor count
# TYPE process_files_max_files gauge
process_files_max_files{application="path-connector-hancock-whitney"} 1048576.0
# HELP process_files_open_files The open file descriptor count
# TYPE process_files_open_files gauge
process_files_open_files{application="path-connector-hancock-whitney"} 183.0
# HELP process_start_time_seconds Start time of the process since unix epoch.
# TYPE process_start_time_seconds gauge
process_start_time_seconds{application="path-connector-hancock-whitney"} 1.786681036208E9
# HELP process_uptime_seconds The uptime of the Java virtual machine
# TYPE process_uptime_seconds gauge
process_uptime_seconds{application="path-connector-hancock-whitney"} 292.291
# HELP system_cpu_count The number of processors available to the Java virtual machine
# TYPE system_cpu_count gauge
system_cpu_count{application="path-connector-hancock-whitney"} 8.0
# HELP system_cpu_usage The "recent cpu usage" of the system the application is running in
# TYPE system_cpu_usage gauge
system_cpu_usage{application="path-connector-hancock-whitney"} 0.20074349442379183
# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time
# TYPE system_load_average_1m gauge
system_load_average_1m{application="path-connector-hancock-whitney"} 15.46630859375
# HELP tomcat_cache_access_total  
# TYPE tomcat_cache_access_total counter
tomcat_cache_access_total{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_cache_hit_total  
# TYPE tomcat_cache_hit_total counter
tomcat_cache_hit_total{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_connections_config_max_connections  
# TYPE tomcat_connections_config_max_connections gauge
tomcat_connections_config_max_connections{application="path-connector-hancock-whitney",name="http-nio-13024"} 8192.0
# HELP tomcat_connections_current_connections  
# TYPE tomcat_connections_current_connections gauge
tomcat_connections_current_connections{application="path-connector-hancock-whitney",name="http-nio-13024"} 2.0
# HELP tomcat_connections_keepalive_current_connections  
# TYPE tomcat_connections_keepalive_current_connections gauge
tomcat_connections_keepalive_current_connections{application="path-connector-hancock-whitney",name="http-nio-13024"} 1.0
# HELP tomcat_global_error_total  
# TYPE tomcat_global_error_total counter
tomcat_global_error_total{application="path-connector-hancock-whitney",name="http-nio-13024"} 1.0
# HELP tomcat_global_received_bytes_total  
# TYPE tomcat_global_received_bytes_total counter
tomcat_global_received_bytes_total{application="path-connector-hancock-whitney",name="http-nio-13024"} 0.0
# HELP tomcat_global_request_max_seconds  
# TYPE tomcat_global_request_max_seconds gauge
tomcat_global_request_max_seconds{application="path-connector-hancock-whitney",name="http-nio-13024"} 0.257
# HELP tomcat_global_request_seconds  
# TYPE tomcat_global_request_seconds summary
tomcat_global_request_seconds_count{application="path-connector-hancock-whitney",name="http-nio-13024"} 3
tomcat_global_request_seconds_sum{application="path-connector-hancock-whitney",name="http-nio-13024"} 0.362
# HELP tomcat_global_sent_bytes_total  
# TYPE tomcat_global_sent_bytes_total counter
tomcat_global_sent_bytes_total{application="path-connector-hancock-whitney",name="http-nio-13024"} 39258.0
# HELP tomcat_servlet_error_total  
# TYPE tomcat_servlet_error_total counter
tomcat_servlet_error_total{application="path-connector-hancock-whitney",name="dispatcherServlet"} 1.0
# HELP tomcat_servlet_request_max_seconds  
# TYPE tomcat_servlet_request_max_seconds gauge
tomcat_servlet_request_max_seconds{application="path-connector-hancock-whitney",name="dispatcherServlet"} 0.236
# HELP tomcat_servlet_request_seconds  
# TYPE tomcat_servlet_request_seconds summary
tomcat_servlet_request_seconds_count{application="path-connector-hancock-whitney",name="dispatcherServlet"} 4
tomcat_servlet_request_seconds_sum{application="path-connector-hancock-whitney",name="dispatcherServlet"} 0.315
# HELP tomcat_sessions_active_current_sessions  
# TYPE tomcat_sessions_active_current_sessions gauge
tomcat_sessions_active_current_sessions{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_sessions_active_max_sessions  
# TYPE tomcat_sessions_active_max_sessions gauge
tomcat_sessions_active_max_sessions{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_sessions_alive_max_seconds  
# TYPE tomcat_sessions_alive_max_seconds gauge
tomcat_sessions_alive_max_seconds{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_sessions_created_sessions_total  
# TYPE tomcat_sessions_created_sessions_total counter
tomcat_sessions_created_sessions_total{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_sessions_expired_sessions_total  
# TYPE tomcat_sessions_expired_sessions_total counter
tomcat_sessions_expired_sessions_total{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_sessions_rejected_sessions_total  
# TYPE tomcat_sessions_rejected_sessions_total counter
tomcat_sessions_rejected_sessions_total{application="path-connector-hancock-whitney"} 0.0
# HELP tomcat_threads_busy_threads  
# TYPE tomcat_threads_busy_threads gauge
tomcat_threads_busy_threads{application="path-connector-hancock-whitney",name="http-nio-13024"} 1.0
# HELP tomcat_threads_config_max_threads  
# TYPE tomcat_threads_config_max_threads gauge
tomcat_threads_config_max_threads{application="path-connector-hancock-whitney",name="http-nio-13024"} 200.0
# HELP tomcat_threads_current_threads  
# TYPE tomcat_threads_current_threads gauge
tomcat_threads_current_threads{application="path-connector-hancock-whitney",name="http-nio-13024"} 10.0

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant