|
2 | 2 |
|
3 | 3 | import java.io.IOException; |
4 | 4 | import java.lang.reflect.Array; |
5 | | -import java.util.Arrays; |
6 | | -import java.util.Objects; |
| 5 | +import java.util.*; |
7 | 6 |
|
8 | 7 | import com.fasterxml.jackson.annotation.JsonFormat; |
9 | 8 |
|
10 | 9 | import com.fasterxml.jackson.core.*; |
| 10 | + |
11 | 11 | import com.fasterxml.jackson.databind.*; |
12 | 12 | import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; |
13 | 13 | import com.fasterxml.jackson.databind.cfg.CoercionAction; |
14 | 14 | import com.fasterxml.jackson.databind.cfg.CoercionInputShape; |
15 | 15 | import com.fasterxml.jackson.databind.deser.ContextualDeserializer; |
16 | 16 | import com.fasterxml.jackson.databind.deser.NullValueProvider; |
| 17 | +import com.fasterxml.jackson.databind.deser.UnresolvedForwardReference; |
| 18 | +import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; |
17 | 19 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; |
18 | 20 | import com.fasterxml.jackson.databind.type.ArrayType; |
19 | 21 | import com.fasterxml.jackson.databind.type.LogicalType; |
20 | 22 | import com.fasterxml.jackson.databind.util.AccessPattern; |
| 23 | +import com.fasterxml.jackson.databind.util.ClassUtil; |
21 | 24 | import com.fasterxml.jackson.databind.util.ObjectBuffer; |
22 | 25 |
|
23 | 26 | /** |
@@ -196,10 +199,17 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) |
196 | 199 | if (!p.isExpectedStartArrayToken()) { |
197 | 200 | return handleNonArray(p, ctxt); |
198 | 201 | } |
199 | | - |
| 202 | + if (_elementDeserializer.getObjectIdReader() != null) { |
| 203 | + return _deserializeWithObjectId(p, ctxt); |
| 204 | + } |
200 | 205 | final ObjectBuffer buffer = ctxt.leaseObjectBuffer(); |
201 | 206 | Object[] chunk = buffer.resetAndStart(); |
202 | 207 | int ix = 0; |
| 208 | + return _deserialize(p, ctxt, buffer, ix, chunk); |
| 209 | + } |
| 210 | + |
| 211 | + protected Object[] _deserialize(JsonParser p, DeserializationContext ctxt, |
| 212 | + final ObjectBuffer buffer, int ix, Object[] chunk) throws JsonMappingException { |
203 | 213 | JsonToken t; |
204 | 214 |
|
205 | 215 | try { |
@@ -245,6 +255,54 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) |
245 | 255 | return result; |
246 | 256 | } |
247 | 257 |
|
| 258 | + protected Object[] _deserializeWithObjectId(JsonParser p, DeserializationContext ctxt) throws JsonMappingException { |
| 259 | + final ObjectArrayReferringAccumulator acc = new ObjectArrayReferringAccumulator(_untyped, _elementClass); |
| 260 | + |
| 261 | + JsonToken t; |
| 262 | + |
| 263 | + int ix = 0; |
| 264 | + try { |
| 265 | + while ((t = p.nextToken()) != JsonToken.END_ARRAY) { |
| 266 | + try { |
| 267 | + Object value; |
| 268 | + |
| 269 | + if (t == JsonToken.VALUE_NULL) { |
| 270 | + if (_skipNullValues) { |
| 271 | + continue; |
| 272 | + } |
| 273 | + value = null; |
| 274 | + } else { |
| 275 | + value = _deserializeNoNullChecks(p, ctxt); |
| 276 | + } |
| 277 | + |
| 278 | + if (value == null) { |
| 279 | + value = _nullProvider.getNullValue(ctxt); |
| 280 | + |
| 281 | + if (value == null && _skipNullValues) { |
| 282 | + continue; |
| 283 | + } |
| 284 | + } |
| 285 | + acc.add(value); |
| 286 | + } catch (UnresolvedForwardReference reference) { |
| 287 | + if (acc == null) { |
| 288 | + throw reference; |
| 289 | + } |
| 290 | + ArrayReferring referring = new ArrayReferring(reference, _elementClass, acc); |
| 291 | + reference.getRoid().appendReferring(referring); |
| 292 | + } |
| 293 | + ++ix; |
| 294 | + } |
| 295 | + } catch (Exception e) { |
| 296 | + boolean wrap = (ctxt == null) || ctxt.isEnabled(DeserializationFeature.WRAP_EXCEPTIONS); |
| 297 | + if (!wrap) { |
| 298 | + ClassUtil.throwIfRTE(e); |
| 299 | + } |
| 300 | + throw JsonMappingException.wrapWithPath(e, acc.buildArray(), ix); |
| 301 | + } |
| 302 | + |
| 303 | + return acc.buildArray(); |
| 304 | + } |
| 305 | + |
248 | 306 | @Override |
249 | 307 | public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, |
250 | 308 | TypeDeserializer typeDeserializer) |
@@ -425,4 +483,59 @@ protected Object _deserializeNoNullChecks(JsonParser p, DeserializationContext c |
425 | 483 | } |
426 | 484 | return _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer); |
427 | 485 | } |
| 486 | + |
| 487 | + // @since 2.21 |
| 488 | + private static class ObjectArrayReferringAccumulator { |
| 489 | + private final boolean _untyped; |
| 490 | + private final Class<?> _elementType; |
| 491 | + private final List<Object> _accumulator = new ArrayList<>(); |
| 492 | + |
| 493 | + private Object[] _array; |
| 494 | + |
| 495 | + ObjectArrayReferringAccumulator(boolean untyped, Class<?> elementType) { |
| 496 | + _untyped = untyped; |
| 497 | + _elementType = elementType; |
| 498 | + } |
| 499 | + |
| 500 | + void add(Object value) { |
| 501 | + _accumulator.add(value); |
| 502 | + } |
| 503 | + |
| 504 | + Object[] buildArray() { |
| 505 | + if (_untyped) { |
| 506 | + _array = new Object[_accumulator.size()]; |
| 507 | + } else { |
| 508 | + _array = (Object[]) Array.newInstance(_elementType, _accumulator.size()); |
| 509 | + } |
| 510 | + for (int i = 0; i < _accumulator.size(); i++) { |
| 511 | + if (!(_accumulator.get(i) instanceof ArrayReferring)) { |
| 512 | + _array[i] = _accumulator.get(i); |
| 513 | + } |
| 514 | + } |
| 515 | + return _array; |
| 516 | + } |
| 517 | + } |
| 518 | + |
| 519 | + private static class ArrayReferring extends Referring { |
| 520 | + private final ObjectArrayReferringAccumulator _parent; |
| 521 | + |
| 522 | + ArrayReferring(UnresolvedForwardReference ref, |
| 523 | + Class<?> type, |
| 524 | + ObjectArrayReferringAccumulator acc) { |
| 525 | + super(ref, type); |
| 526 | + _parent = acc; |
| 527 | + _parent._accumulator.add(this); |
| 528 | + } |
| 529 | + |
| 530 | + @Override |
| 531 | + public void handleResolvedForwardReference(Object id, Object value) throws JacksonException { |
| 532 | + for (int i = 0; i < _parent._accumulator.size(); i++) { |
| 533 | + if (_parent._accumulator.get(i) == this) { |
| 534 | + _parent._array[i] = value; |
| 535 | + return; |
| 536 | + } |
| 537 | + } |
| 538 | + throw new IllegalArgumentException("Trying to resolve unknown reference: " + id); |
| 539 | + } |
| 540 | + } |
428 | 541 | } |
0 commit comments