This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/4.1.x-fixes by this push:
     new 9f5c37e2928 Apply the JSON depth limit to writes as well (#3152)
9f5c37e2928 is described below

commit 9f5c37e29287a5ed6be9cc1152056747e4951e2c
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu May 28 14:54:38 2026 +0100

    Apply the JSON depth limit to writes as well (#3152)
    
    (cherry picked from commit 51b7f0d087a075de17af044c87cf9ce6be002fe7)
---
 .../json/basic/JsonMapObjectReaderWriter.java      | 45 +++++++++++++++++-----
 .../json/basic/JsonMapObjectReaderWriterTest.java  | 16 ++++++++
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git 
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
 
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
index 7ea3ca1d926..f83e48ad3ad 100644
--- 
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
+++ 
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
@@ -75,13 +75,13 @@ public class JsonMapObjectReaderWriter {
 
     public String toJson(Map<String, Object> map) {
         StringBuilder sb = new StringBuilder();
-        toJsonInternal(new StringBuilderOutput(sb), map);
+        toJsonInternal(new StringBuilderOutput(sb), map, 0);
         return sb.toString();
     }
 
     public String toJson(List<Object> list) {
         StringBuilder sb = new StringBuilder();
-        toJsonInternal(new StringBuilderOutput(sb), list);
+        toJsonInternal(new StringBuilderOutput(sb), list, 0);
         return sb.toString();
     }
 
@@ -90,29 +90,49 @@ public class JsonMapObjectReaderWriter {
     }
 
     public void toJson(Map<String, Object> map, OutputStream os) {
-        toJsonInternal(new StreamOutput(os), map);
+        toJsonInternal(new StreamOutput(os), map, 0);
     }
 
     protected void toJsonInternal(Output out, Map<String, Object> map) {
+        toJsonInternal(out, map, 0);
+    }
+
+    private void toJsonInternal(Output out, Map<String, Object> map, int 
depth) {
+        if (depth > MAX_RECURSION_DEPTH) {
+            throw new UncheckedIOException(new IOException(
+                "JSON nesting depth exceeds maximum of " + 
MAX_RECURSION_DEPTH));
+        }
         out.append(OBJECT_START);
         for (Iterator<Map.Entry<String, Object>> it = 
map.entrySet().iterator(); it.hasNext();) {
             Map.Entry<String, Object> entry = it.next();
             
out.append(DQUOTE).append(escapeJson(entry.getKey())).append(DQUOTE);
             out.append(COLON);
-            toJsonInternal(out, entry.getValue(), it.hasNext());
+            toJsonInternal(out, entry.getValue(), it.hasNext(), depth);
         }
         out.append(OBJECT_END);
     }
 
     protected void toJsonInternal(Output out, Object[] array) {
-        toJsonInternal(out, Arrays.asList(array));
+        toJsonInternal(out, array, 0);
+    }
+
+    private void toJsonInternal(Output out, Object[] array, int depth) {
+        toJsonInternal(out, Arrays.asList(array), depth);
     }
 
     protected void toJsonInternal(Output out, Collection<?> coll) {
+        toJsonInternal(out, coll, 0);
+    }
+
+    private void toJsonInternal(Output out, Collection<?> coll, int depth) {
+        if (depth > MAX_RECURSION_DEPTH) {
+            throw new UncheckedIOException(new IOException(
+                "JSON nesting depth exceeds maximum of " + 
MAX_RECURSION_DEPTH));
+        }
         out.append(ARRAY_START);
         formatIfNeeded(out);
         for (Iterator<?> iter = coll.iterator(); iter.hasNext();) {
-            toJsonInternal(out, iter.next(), iter.hasNext());
+            toJsonInternal(out, iter.next(), iter.hasNext(), depth);
         }
         formatIfNeeded(out);
         out.append(ARRAY_END);
@@ -120,16 +140,21 @@ public class JsonMapObjectReaderWriter {
 
     @SuppressWarnings("unchecked")
     protected void toJsonInternal(Output out, Object value, boolean hasNext) {
+        toJsonInternal(out, value, hasNext, 0);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void toJsonInternal(Output out, Object value, boolean hasNext, int 
depth) {
         if (value == null) {
             out.append(null);
         } else if (JsonMapObject.class.isAssignableFrom(value.getClass())) {
-            out.append(toJson((JsonMapObject)value));
+            toJsonInternal(out, ((JsonMapObject)value).asMap(), depth + 1);
         } else if (value.getClass().isArray()) {
-            toJsonInternal(out, (Object[])value);
+            toJsonInternal(out, (Object[])value, depth + 1);
         } else if (Collection.class.isAssignableFrom(value.getClass())) {
-            toJsonInternal(out, (Collection<?>)value);
+            toJsonInternal(out, (Collection<?>)value, depth + 1);
         } else if (Map.class.isAssignableFrom(value.getClass())) {
-            toJsonInternal(out, (Map<String, Object>)value);
+            toJsonInternal(out, (Map<String, Object>)value, depth + 1);
         } else {
             boolean quotesNeeded = checkQuotesNeeded(value);
             if (quotesNeeded) {
diff --git 
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
 
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
index a8583cce40e..805f56b5c2f 100644
--- 
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
+++ 
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
@@ -430,4 +430,20 @@ public class JsonMapObjectReaderWriterTest {
         new JsonMapObjectReaderWriter().fromJson(sb.toString());
     }
 
+    @Test(expected = UncheckedIOException.class)
+    public void testWriterPathDeeplyNestedMapThrowsUncheckedIOException() {
+        new JsonMapObjectReaderWriter().toJson(createNestedMap(20000));
+    }
+
+    private Map<String, Object> createNestedMap(int depth) {
+        Map<String, Object> root = new HashMap<>();
+        Map<String, Object> current = root;
+        for (int i = 0; i < depth; i++) {
+            Map<String, Object> child = new HashMap<>();
+            current.put("k", child);
+            current = child;
+        }
+        return root;
+    }
+
 }

Reply via email to