1818public final class JsonObjectReader implements ObjectReader {
1919
2020 private final @ NotNull JsonReader jsonReader ;
21+ private int depth = 0 ;
2122
2223 public JsonObjectReader (Reader in ) {
2324 this .jsonReader = new JsonReader (in );
@@ -84,10 +85,18 @@ public float nextFloat() throws IOException {
8485
8586 @ Override
8687 public void nextUnknown (ILogger logger , Map <String , Object > unknown , String name ) {
88+ final int startDepth = depth ;
89+ JsonToken startToken = JsonToken .END_DOCUMENT ;
8790 try {
91+ startToken = peek ();
8892 unknown .put (name , nextObjectOrNull ());
8993 } catch (Exception exception ) {
9094 logger .log (SentryLevel .ERROR , exception , "Error deserializing unknown key: %s" , name );
95+ try {
96+ recoverValue (startDepth , startToken );
97+ } catch (Exception ignored ) {
98+ // stream is unrecoverable
99+ }
91100 }
92101 }
93102
@@ -98,18 +107,28 @@ public void nextUnknown(ILogger logger, Map<String, Object> unknown, String name
98107 jsonReader .nextNull ();
99108 return null ;
100109 }
101- jsonReader . beginArray ();
110+ beginArray ();
102111 List <T > list = new ArrayList <>();
103112 if (jsonReader .hasNext ()) {
104113 do {
114+ final int startDepth = depth ;
115+ final JsonToken startToken = peek ();
105116 try {
106117 list .add (deserializer .deserialize (this , logger ));
107118 } catch (Exception e ) {
108- logger .log (SentryLevel .WARNING , "Failed to deserialize object in list." , e );
119+ if (!recoverAfterValueFailure (
120+ logger ,
121+ e ,
122+ "Failed to deserialize object in list." ,
123+ "Stream unrecoverable, aborting list deserialization." ,
124+ startDepth ,
125+ startToken )) {
126+ break ;
127+ }
109128 }
110129 } while (jsonReader .peek () == JsonToken .BEGIN_OBJECT );
111130 }
112- jsonReader . endArray ();
131+ endArray ();
113132 return list ;
114133 }
115134
@@ -120,20 +139,30 @@ public void nextUnknown(ILogger logger, Map<String, Object> unknown, String name
120139 jsonReader .nextNull ();
121140 return null ;
122141 }
123- jsonReader . beginObject ();
142+ beginObject ();
124143 Map <String , T > map = new HashMap <>();
125144 if (jsonReader .hasNext ()) {
126145 do {
146+ final String key = jsonReader .nextName ();
147+ final int startDepth = depth ;
148+ final JsonToken startToken = peek ();
127149 try {
128- String key = jsonReader .nextName ();
129150 map .put (key , deserializer .deserialize (this , logger ));
130151 } catch (Exception e ) {
131- logger .log (SentryLevel .WARNING , "Failed to deserialize object in map." , e );
152+ if (!recoverAfterValueFailure (
153+ logger ,
154+ e ,
155+ "Failed to deserialize object in map." ,
156+ "Stream unrecoverable, aborting map deserialization." ,
157+ startDepth ,
158+ startToken )) {
159+ break ;
160+ }
132161 }
133162 } while (jsonReader .peek () == JsonToken .BEGIN_OBJECT || jsonReader .peek () == JsonToken .NAME );
134163 }
135164
136- jsonReader . endObject ();
165+ endObject ();
137166 return map ;
138167 }
139168
@@ -151,9 +180,23 @@ public void nextUnknown(ILogger logger, Map<String, Object> unknown, String name
151180 if (hasNext ()) {
152181 do {
153182 final @ NotNull String key = nextName ();
154- final @ Nullable List <T > list = nextListOrNull (logger , deserializer );
155- if (list != null ) {
156- result .put (key , list );
183+ final int startDepth = depth ;
184+ final JsonToken startToken = peek ();
185+ try {
186+ final @ Nullable List <T > list = nextListOrNull (logger , deserializer );
187+ if (list != null ) {
188+ result .put (key , list );
189+ }
190+ } catch (Exception e ) {
191+ if (!recoverAfterValueFailure (
192+ logger ,
193+ e ,
194+ "Failed to deserialize list in map." ,
195+ "Stream unrecoverable, aborting map-of-lists deserialization." ,
196+ startDepth ,
197+ startToken )) {
198+ break ;
199+ }
157200 }
158201 } while (peek () == JsonToken .BEGIN_OBJECT || peek () == JsonToken .NAME );
159202 }
@@ -219,21 +262,25 @@ public void nextUnknown(ILogger logger, Map<String, Object> unknown, String name
219262 @ Override
220263 public void beginObject () throws IOException {
221264 jsonReader .beginObject ();
265+ depth ++;
222266 }
223267
224268 @ Override
225269 public void endObject () throws IOException {
226270 jsonReader .endObject ();
271+ depth --;
227272 }
228273
229274 @ Override
230275 public void beginArray () throws IOException {
231276 jsonReader .beginArray ();
277+ depth ++;
232278 }
233279
234280 @ Override
235281 public void endArray () throws IOException {
236282 jsonReader .endArray ();
283+ depth --;
237284 }
238285
239286 @ Override
@@ -281,6 +328,42 @@ public void skipValue() throws IOException {
281328 jsonReader .skipValue ();
282329 }
283330
331+ private boolean recoverAfterValueFailure (
332+ final @ NotNull ILogger logger ,
333+ final @ NotNull Exception error ,
334+ final @ NotNull String warningMessage ,
335+ final @ NotNull String unrecoverableMessage ,
336+ final int startDepth ,
337+ final @ NotNull JsonToken startToken ) {
338+ logger .log (SentryLevel .WARNING , warningMessage , error );
339+ try {
340+ recoverValue (startDepth , startToken );
341+ return true ;
342+ } catch (Exception recoveryException ) {
343+ logger .log (SentryLevel .ERROR , unrecoverableMessage , recoveryException );
344+ return false ;
345+ }
346+ }
347+
348+ private void recoverValue (final int startDepth , final @ NotNull JsonToken startToken )
349+ throws IOException {
350+ final boolean enteredNestedValue = depth > startDepth ;
351+ while (depth > startDepth ) {
352+ final JsonToken token = peek ();
353+ if (token == JsonToken .END_OBJECT ) {
354+ endObject ();
355+ } else if (token == JsonToken .END_ARRAY ) {
356+ endArray ();
357+ } else {
358+ skipValue ();
359+ }
360+ }
361+
362+ if (!enteredNestedValue && peek () == startToken ) {
363+ skipValue ();
364+ }
365+ }
366+
284367 @ Override
285368 public void close () throws IOException {
286369 jsonReader .close ();
0 commit comments