Skip to content

Support for Jackson 3 in Dropwizard Metrics 5.x #5116

@joschi

Description

@joschi

Port #5101 to release/5.0.x branch.

Diff from release/4.2.x branch:

diff -ru metrics-json/pom.xml metrics-jackson3/pom.xml
--- metrics-json/pom.xml        2026-01-26 00:35:19
+++ metrics-jackson3/pom.xml    2026-01-26 00:35:19
@@ -8,17 +8,18 @@
         <version>4.2.39-SNAPSHOT</version>
     </parent>

-    <artifactId>metrics-json</artifactId>
-    <name>Jackson Integration for Metrics</name>
+    <artifactId>metrics-jackson3</artifactId>
+    <name>Jackson 3 Integration for Metrics</name>
     <packaging>bundle</packaging>
     <description>
         A set of Jackson modules which provide serializers for most Metrics classes.
     </description>

     <properties>
-        <javaModuleName>com.codahale.metrics.json</javaModuleName>
-        <jackson.version>2.12.7</jackson.version>
-        <jackson-databind.version>2.12.7.2</jackson-databind.version>
+        <javaModuleName>com.codahale.metrics.jackson3</javaModuleName>
+        <maven.compiler.release>17</maven.compiler.release>
+        <jackson.version>3.0.3</jackson.version>
+        <jackson-databind.version>3.0.3</jackson-databind.version>
     </properties>

     <dependencyManagement>
@@ -49,12 +50,12 @@
             <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
+            <groupId>tools.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
             <version>${jackson.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
+            <groupId>tools.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             <version>${jackson-databind.version}</version>
         </dependency>
diff -ru metrics-json/src/main/java/com/codahale/metrics/jackson3/HealthCheckModule.java metrics-jackson3/src/main/java/com/codahale/metrics/jackson3/HealthCheckModule.java
--- metrics-json/src/main/java/com/codahale/metrics/jackson3/HealthCheckModule.java     2025-09-26 22:10:24
+++ metrics-jackson3/src/main/java/com/codahale/metrics/jackson3/HealthCheckModule.java 2026-01-26 00:35:19
@@ -1,18 +1,18 @@
-package com.codahale.metrics.json;
+package com.codahale.metrics.jackson3;

 import com.codahale.metrics.health.HealthCheck;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.Version;
-import com.fasterxml.jackson.databind.Module;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.module.SimpleSerializers;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.core.Version;
+import tools.jackson.databind.JacksonModule;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.module.SimpleSerializers;
+import tools.jackson.databind.ser.std.StdSerializer;

 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;

-public class HealthCheckModule extends Module {
+public class HealthCheckModule extends JacksonModule {
     private static class HealthCheckResultSerializer extends StdSerializer<HealthCheck.Result> {

         private static final long serialVersionUID = 1L;
@@ -24,35 +24,39 @@
         @Override
         public void serialize(HealthCheck.Result result,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
-            json.writeBooleanField("healthy", result.isHealthy());
+            json.writeBooleanProperty("healthy", result.isHealthy());

             final String message = result.getMessage();
             if (message != null) {
-                json.writeStringField("message", message);
+                json.writeStringProperty("message", message);
             }

-            serializeThrowable(json, result.getError(), "error");
-            json.writeNumberField("duration", result.getDuration());
+            try {
+                serializeThrowable(json, result.getError(), "error");
+            } catch (IOException ioe) {
+                throw new RuntimeException(ioe);
+            }
+            json.writeNumberProperty("duration", result.getDuration());

             Map<String, Object> details = result.getDetails();
             if (details != null && !details.isEmpty()) {
                 for (Map.Entry<String, Object> e : details.entrySet()) {
-                    json.writeObjectField(e.getKey(), e.getValue());
+                    json.writePOJOProperty(e.getKey(), e.getValue());
                 }
             }

-            json.writeStringField("timestamp", result.getTimestamp());
+            json.writeStringProperty("timestamp", result.getTimestamp());
             json.writeEndObject();
         }

         private void serializeThrowable(JsonGenerator json, Throwable error, String name) throws IOException {
             if (error != null) {
-                json.writeObjectFieldStart(name);
-                json.writeStringField("type", error.getClass().getTypeName());
-                json.writeStringField("message", error.getMessage());
-                json.writeArrayFieldStart("stack");
+                json.writeObjectPropertyStart(name);
+                json.writeStringProperty("type", error.getClass().getTypeName());
+                json.writeStringProperty("message", error.getMessage());
+                json.writeArrayPropertyStart("stack");
                 for (StackTraceElement element : error.getStackTrace()) {
                     json.writeString(element.toString());
                 }
diff -ru metrics-json/src/main/java/com/codahale/metrics/jackson3/MetricsModule.java metrics-jackson3/src/main/java/com/codahale/metrics/jackson3/MetricsModule.java
--- metrics-json/src/main/java/com/codahale/metrics/jackson3/MetricsModule.java 2025-09-26 22:10:24
+++ metrics-jackson3/src/main/java/com/codahale/metrics/jackson3/MetricsModule.java     2026-01-26 00:35:19
@@ -1,4 +1,4 @@
-package com.codahale.metrics.json;
+package com.codahale.metrics.jackson3;

 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Gauge;
@@ -8,19 +8,18 @@
 import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.Snapshot;
 import com.codahale.metrics.Timer;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.Version;
-import com.fasterxml.jackson.databind.Module;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.module.SimpleSerializers;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.core.Version;
+import tools.jackson.databind.JacksonModule;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.module.SimpleSerializers;
+import tools.jackson.databind.ser.std.StdSerializer;

-import java.io.IOException;
 import java.util.Arrays;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;

-public class MetricsModule extends Module {
+public class MetricsModule extends JacksonModule {
     static final Version VERSION = new Version(4, 0, 0, "", "io.dropwizard.metrics", "metrics-json");

     @SuppressWarnings("rawtypes")
@@ -35,14 +34,14 @@
         @Override
         public void serialize(Gauge gauge,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
             final Object value;
             try {
                 value = gauge.getValue();
-                json.writeObjectField("value", value);
+                json.writePOJOProperty("value", value);
             } catch (RuntimeException e) {
-                json.writeObjectField("error", e.toString());
+                json.writePOJOProperty("error", e.toString());
             }
             json.writeEndObject();
         }
@@ -59,9 +58,9 @@
         @Override
         public void serialize(Counter counter,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
-            json.writeNumberField("count", counter.getCount());
+            json.writeNumberProperty("count", counter.getCount());
             json.writeEndObject();
         }
     }
@@ -80,25 +79,25 @@
         @Override
         public void serialize(Histogram histogram,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
             final Snapshot snapshot = histogram.getSnapshot();
-            json.writeNumberField("count", histogram.getCount());
-            json.writeNumberField("max", snapshot.getMax());
-            json.writeNumberField("mean", snapshot.getMean());
-            json.writeNumberField("min", snapshot.getMin());
-            json.writeNumberField("p50", snapshot.getMedian());
-            json.writeNumberField("p75", snapshot.get75thPercentile());
-            json.writeNumberField("p95", snapshot.get95thPercentile());
-            json.writeNumberField("p98", snapshot.get98thPercentile());
-            json.writeNumberField("p99", snapshot.get99thPercentile());
-            json.writeNumberField("p999", snapshot.get999thPercentile());
+            json.writeNumberProperty("count", histogram.getCount());
+            json.writeNumberProperty("max", snapshot.getMax());
+            json.writeNumberProperty("mean", snapshot.getMean());
+            json.writeNumberProperty("min", snapshot.getMin());
+            json.writeNumberProperty("p50", snapshot.getMedian());
+            json.writeNumberProperty("p75", snapshot.get75thPercentile());
+            json.writeNumberProperty("p95", snapshot.get95thPercentile());
+            json.writeNumberProperty("p98", snapshot.get98thPercentile());
+            json.writeNumberProperty("p99", snapshot.get99thPercentile());
+            json.writeNumberProperty("p999", snapshot.get999thPercentile());

             if (showSamples) {
-                json.writeObjectField("values", snapshot.getValues());
+                json.writePOJOProperty("values", snapshot.getValues());
             }

-            json.writeNumberField("stddev", snapshot.getStdDev());
+            json.writeNumberProperty("stddev", snapshot.getStdDev());
             json.writeEndObject();
         }
     }
@@ -119,14 +118,14 @@
         @Override
         public void serialize(Meter meter,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
-            json.writeNumberField("count", meter.getCount());
-            json.writeNumberField("m15_rate", meter.getFifteenMinuteRate() * rateFactor);
-            json.writeNumberField("m1_rate", meter.getOneMinuteRate() * rateFactor);
-            json.writeNumberField("m5_rate", meter.getFiveMinuteRate() * rateFactor);
-            json.writeNumberField("mean_rate", meter.getMeanRate() * rateFactor);
-            json.writeStringField("units", rateUnit);
+            json.writeNumberProperty("count", meter.getCount());
+            json.writeNumberProperty("m15_rate", meter.getFifteenMinuteRate() * rateFactor);
+            json.writeNumberProperty("m1_rate", meter.getOneMinuteRate() * rateFactor);
+            json.writeNumberProperty("m5_rate", meter.getFiveMinuteRate() * rateFactor);
+            json.writeNumberProperty("mean_rate", meter.getMeanRate() * rateFactor);
+            json.writeStringProperty("units", rateUnit);
             json.writeEndObject();
         }
     }
@@ -155,20 +154,20 @@
         @Override
         public void serialize(Timer timer,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
             final Snapshot snapshot = timer.getSnapshot();
-            json.writeNumberField("count", timer.getCount());
-            json.writeNumberField("max", snapshot.getMax() * durationFactor);
-            json.writeNumberField("mean", snapshot.getMean() * durationFactor);
-            json.writeNumberField("min", snapshot.getMin() * durationFactor);
+            json.writeNumberProperty("count", timer.getCount());
+            json.writeNumberProperty("max", snapshot.getMax() * durationFactor);
+            json.writeNumberProperty("mean", snapshot.getMean() * durationFactor);
+            json.writeNumberProperty("min", snapshot.getMin() * durationFactor);

-            json.writeNumberField("p50", snapshot.getMedian() * durationFactor);
-            json.writeNumberField("p75", snapshot.get75thPercentile() * durationFactor);
-            json.writeNumberField("p95", snapshot.get95thPercentile() * durationFactor);
-            json.writeNumberField("p98", snapshot.get98thPercentile() * durationFactor);
-            json.writeNumberField("p99", snapshot.get99thPercentile() * durationFactor);
-            json.writeNumberField("p999", snapshot.get999thPercentile() * durationFactor);
+            json.writeNumberProperty("p50", snapshot.getMedian() * durationFactor);
+            json.writeNumberProperty("p75", snapshot.get75thPercentile() * durationFactor);
+            json.writeNumberProperty("p95", snapshot.get95thPercentile() * durationFactor);
+            json.writeNumberProperty("p98", snapshot.get98thPercentile() * durationFactor);
+            json.writeNumberProperty("p99", snapshot.get99thPercentile() * durationFactor);
+            json.writeNumberProperty("p999", snapshot.get999thPercentile() * durationFactor);

             if (showSamples) {
                 final long[] values = snapshot.getValues();
@@ -176,16 +175,16 @@
                 for (int i = 0; i < values.length; i++) {
                     scaledValues[i] = values[i] * durationFactor;
                 }
-                json.writeObjectField("values", scaledValues);
+                json.writePOJOProperty("values", scaledValues);
             }

-            json.writeNumberField("stddev", snapshot.getStdDev() * durationFactor);
-            json.writeNumberField("m15_rate", timer.getFifteenMinuteRate() * rateFactor);
-            json.writeNumberField("m1_rate", timer.getOneMinuteRate() * rateFactor);
-            json.writeNumberField("m5_rate", timer.getFiveMinuteRate() * rateFactor);
-            json.writeNumberField("mean_rate", timer.getMeanRate() * rateFactor);
-            json.writeStringField("duration_units", durationUnit);
-            json.writeStringField("rate_units", rateUnit);
+            json.writeNumberProperty("stddev", snapshot.getStdDev() * durationFactor);
+            json.writeNumberProperty("m15_rate", timer.getFifteenMinuteRate() * rateFactor);
+            json.writeNumberProperty("m1_rate", timer.getOneMinuteRate() * rateFactor);
+            json.writeNumberProperty("m5_rate", timer.getFiveMinuteRate() * rateFactor);
+            json.writeNumberProperty("mean_rate", timer.getMeanRate() * rateFactor);
+            json.writeStringProperty("duration_units", durationUnit);
+            json.writeStringProperty("rate_units", rateUnit);
             json.writeEndObject();
         }
     }
@@ -204,14 +203,14 @@
         @Override
         public void serialize(MetricRegistry registry,
                               JsonGenerator json,
-                              SerializerProvider provider) throws IOException {
+                              SerializationContext provider) {
             json.writeStartObject();
-            json.writeStringField("version", VERSION.toString());
-            json.writeObjectField("gauges", registry.getGauges(filter));
-            json.writeObjectField("counters", registry.getCounters(filter));
-            json.writeObjectField("histograms", registry.getHistograms(filter));
-            json.writeObjectField("meters", registry.getMeters(filter));
-            json.writeObjectField("timers", registry.getTimers(filter));
+            json.writeStringProperty("version", VERSION.toString());
+            json.writePOJOProperty("gauges", registry.getGauges(filter));
+            json.writePOJOProperty("counters", registry.getCounters(filter));
+            json.writePOJOProperty("histograms", registry.getHistograms(filter));
+            json.writePOJOProperty("meters", registry.getMeters(filter));
+            json.writePOJOProperty("timers", registry.getTimers(filter));
             json.writeEndObject();
         }
     }
diff -ru metrics-json/src/test/java/com/codahale/metrics/jackson3/HealthCheckModuleTest.java metrics-jackson3/src/test/java/com/codahale/metrics/jackson3/HealthCheckModuleTest.java
--- metrics-json/src/test/java/com/codahale/metrics/jackson3/HealthCheckModuleTest.java 2025-09-26 22:10:24
+++ metrics-jackson3/src/test/java/com/codahale/metrics/jackson3/HealthCheckModuleTest.java     2026-01-26 00:35:19
@@ -1,7 +1,9 @@
-package com.codahale.metrics.json;
+package com.codahale.metrics.jackson3;

 import com.codahale.metrics.health.HealthCheck;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.databind.json.JsonMapper;
+
 import org.junit.Test;

 import java.math.BigDecimal;
@@ -12,7 +14,7 @@
 import static org.assertj.core.api.Assertions.assertThat;

 public class HealthCheckModuleTest {
-    private final ObjectMapper mapper = new ObjectMapper().registerModule(new HealthCheckModule());
+    private final ObjectMapper mapper = JsonMapper.builder().addModule(new HealthCheckModule()).build();

     @Test
     public void serializesAHealthyResult() throws Exception {
diff -ru metrics-json/src/test/java/com/codahale/metrics/jackson3/MetricsModuleTest.java metrics-jackson3/src/test/java/com/codahale/metrics/jackson3/MetricsModuleTest.java
--- metrics-json/src/test/java/com/codahale/metrics/jackson3/MetricsModuleTest.java     2025-09-26 22:10:24
+++ metrics-jackson3/src/test/java/com/codahale/metrics/jackson3/MetricsModuleTest.java 2026-01-26 00:35:19
@@ -1,4 +1,4 @@
-package com.codahale.metrics.json;
+package com.codahale.metrics.jackson3;

 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Gauge;
@@ -8,7 +8,9 @@
 import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.Snapshot;
 import com.codahale.metrics.Timer;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.databind.json.JsonMapper;
+
 import org.junit.Test;

 import java.util.concurrent.TimeUnit;
@@ -18,8 +20,8 @@
 import static org.mockito.Mockito.when;

 public class MetricsModuleTest {
-    private final ObjectMapper mapper = new ObjectMapper().registerModule(
-            new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, false, MetricFilter.ALL));
+    private final ObjectMapper mapper = JsonMapper.builder().addModule(
+            new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, false, MetricFilter.ALL)).build();

     @Test
     public void serializesGauges() throws Exception {
@@ -82,8 +84,8 @@
                         "\"p999\":11.0," +
                         "\"stddev\":5.0}");

-        final ObjectMapper fullMapper = new ObjectMapper().registerModule(
-                new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true, MetricFilter.ALL));
+        final ObjectMapper fullMapper = JsonMapper.builder().addModule(
+                new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true, MetricFilter.ALL)).build();

         assertThat(fullMapper.writeValueAsString(histogram))
                 .isEqualTo("{" +
@@ -169,8 +171,8 @@
                         "\"duration_units\":\"milliseconds\"," +
                         "\"rate_units\":\"calls/second\"}");

-        final ObjectMapper fullMapper = new ObjectMapper().registerModule(
-                new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true, MetricFilter.ALL));
+        final ObjectMapper fullMapper = JsonMapper.builder().addModule(
+                new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true, MetricFilter.ALL)).build();

         assertThat(fullMapper.writeValueAsString(timer))
                 .isEqualTo("{" +

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions