1 package com.fasterxml.jackson.databind.deser.std;
2
3 import java.io.IOException;
4 import java.lang.reflect.Array;
5
6 import com.fasterxml.jackson.annotation.JsonFormat;
7
8 import com.fasterxml.jackson.core.*;
9
10 import com.fasterxml.jackson.databind.*;
11 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
12 import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
13 import com.fasterxml.jackson.databind.deser.NullValueProvider;
14 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
15 import com.fasterxml.jackson.databind.util.AccessPattern;
16 import com.fasterxml.jackson.databind.util.ObjectBuffer;
17
18
21 @JacksonStdImpl
22 public class ObjectArrayDeserializer
23 extends ContainerDeserializerBase<Object[]>
24 implements ContextualDeserializer
25 {
26 private static final long serialVersionUID = 1L;
27
28 protected final static Object[] NO_OBJECTS = new Object[0];
29
30
31
32
36 protected final boolean _untyped;
37
38
42 protected final Class<?> _elementClass;
43
44
47 protected JsonDeserializer<Object> _elementDeserializer;
48
49
53 protected final TypeDeserializer _elementTypeDeserializer;
54
55
60
61 public ObjectArrayDeserializer(JavaType arrayType,
62 JsonDeserializer<Object> elemDeser, TypeDeserializer elemTypeDeser)
63 {
64 super(arrayType, null, null);
65 _elementClass = arrayType.getContentType().getRawClass();
66 _untyped = (_elementClass == Object.class);
67 _elementDeserializer = elemDeser;
68 _elementTypeDeserializer = elemTypeDeser;
69 }
70
71 protected ObjectArrayDeserializer(ObjectArrayDeserializer base,
72 JsonDeserializer<Object> elemDeser, TypeDeserializer elemTypeDeser,
73 NullValueProvider nuller, Boolean unwrapSingle)
74 {
75 super(base, nuller, unwrapSingle);
76 _elementClass = base._elementClass;
77 _untyped = base._untyped;
78
79 _elementDeserializer = elemDeser;
80 _elementTypeDeserializer = elemTypeDeser;
81 }
82
83
86 public ObjectArrayDeserializer withDeserializer(TypeDeserializer elemTypeDeser,
87 JsonDeserializer<?> elemDeser)
88 {
89 return withResolved(elemTypeDeser, elemDeser,
90 _nullProvider, _unwrapSingle);
91 }
92
93
96 @SuppressWarnings("unchecked")
97 public ObjectArrayDeserializer withResolved(TypeDeserializer elemTypeDeser,
98 JsonDeserializer<?> elemDeser, NullValueProvider nuller, Boolean unwrapSingle)
99 {
100 if ((unwrapSingle == _unwrapSingle) && (nuller == _nullProvider)
101 && (elemDeser == _elementDeserializer)
102 && (elemTypeDeser == _elementTypeDeserializer)) {
103 return this;
104 }
105 return new ObjectArrayDeserializer(this,
106 (JsonDeserializer<Object>) elemDeser, elemTypeDeser,
107 nuller, unwrapSingle);
108 }
109
110 @Override
111 public boolean isCachable() {
112
113
114 return (_elementDeserializer == null) && (_elementTypeDeserializer == null);
115 }
116
117 @Override
118 public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
119 BeanProperty property) throws JsonMappingException
120 {
121 JsonDeserializer<?> valueDeser = _elementDeserializer;
122 Boolean unwrapSingle = findFormatFeature(ctxt, property, _containerType.getRawClass(),
123 JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
124
125 valueDeser = findConvertingContentDeserializer(ctxt, property, valueDeser);
126 final JavaType vt = _containerType.getContentType();
127 if (valueDeser == null) {
128 valueDeser = ctxt.findContextualValueDeserializer(vt, property);
129 } else {
130 valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property, vt);
131 }
132 TypeDeserializer elemTypeDeser = _elementTypeDeserializer;
133 if (elemTypeDeser != null) {
134 elemTypeDeser = elemTypeDeser.forProperty(property);
135 }
136 NullValueProvider nuller = findContentNullProvider(ctxt, property, valueDeser);
137 return withResolved(elemTypeDeser, valueDeser, nuller, unwrapSingle);
138 }
139
140
145
146 @Override
147 public JsonDeserializer<Object> getContentDeserializer() {
148 return _elementDeserializer;
149 }
150
151 @Override
152 public AccessPattern getEmptyAccessPattern() {
153
154 return AccessPattern.CONSTANT;
155 }
156
157
158 @Override
159 public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
160 return NO_OBJECTS;
161 }
162
163
168
169 @Override
170 public Object[] deserialize(JsonParser p, DeserializationContext ctxt)
171 throws IOException
172 {
173
174 if (!p.isExpectedStartArrayToken()) {
175 return handleNonArray(p, ctxt);
176 }
177
178 final ObjectBuffer buffer = ctxt.leaseObjectBuffer();
179 Object[] chunk = buffer.resetAndStart();
180 int ix = 0;
181 JsonToken t;
182 final TypeDeserializer typeDeser = _elementTypeDeserializer;
183
184 try {
185 while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
186
187 Object value;
188
189 if (t == JsonToken.VALUE_NULL) {
190 if (_skipNullValues) {
191 continue;
192 }
193 value = _nullProvider.getNullValue(ctxt);
194 } else if (typeDeser == null) {
195 value = _elementDeserializer.deserialize(p, ctxt);
196 } else {
197 value = _elementDeserializer.deserializeWithType(p, ctxt, typeDeser);
198 }
199 if (ix >= chunk.length) {
200 chunk = buffer.appendCompletedChunk(chunk);
201 ix = 0;
202 }
203 chunk[ix++] = value;
204 }
205 } catch (Exception e) {
206 throw JsonMappingException.wrapWithPath(e, chunk, buffer.bufferedSize() + ix);
207 }
208
209 Object[] result;
210
211 if (_untyped) {
212 result = buffer.completeAndClearBuffer(chunk, ix);
213 } else {
214 result = buffer.completeAndClearBuffer(chunk, ix, _elementClass);
215 }
216 ctxt.returnObjectBuffer(buffer);
217 return result;
218 }
219
220 @Override
221 public Object[] deserializeWithType(JsonParser p, DeserializationContext ctxt,
222 TypeDeserializer typeDeserializer)
223 throws IOException
224 {
225
226
227 return (Object[]) typeDeserializer.deserializeTypedFromArray(p, ctxt);
228 }
229
230 @Override
231 public Object[] deserialize(JsonParser p, DeserializationContext ctxt,
232 Object[] intoValue) throws IOException
233 {
234 if (!p.isExpectedStartArrayToken()) {
235 Object[] arr = handleNonArray(p, ctxt);
236 if (arr == null) {
237 return intoValue;
238 }
239 final int offset = intoValue.length;
240 Object[] result = new Object[offset + arr.length];
241 System.arraycopy(intoValue, 0, result, 0, offset);
242 System.arraycopy(arr, 0, result, offset, arr.length);
243 return result;
244 }
245
246 final ObjectBuffer buffer = ctxt.leaseObjectBuffer();
247 int ix = intoValue.length;
248 Object[] chunk = buffer.resetAndStart(intoValue, ix);
249 JsonToken t;
250 final TypeDeserializer typeDeser = _elementTypeDeserializer;
251
252 try {
253 while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
254 Object value;
255
256 if (t == JsonToken.VALUE_NULL) {
257 if (_skipNullValues) {
258 continue;
259 }
260 value = _nullProvider.getNullValue(ctxt);
261 } else if (typeDeser == null) {
262 value = _elementDeserializer.deserialize(p, ctxt);
263 } else {
264 value = _elementDeserializer.deserializeWithType(p, ctxt, typeDeser);
265 }
266 if (ix >= chunk.length) {
267 chunk = buffer.appendCompletedChunk(chunk);
268 ix = 0;
269 }
270 chunk[ix++] = value;
271 }
272 } catch (Exception e) {
273 throw JsonMappingException.wrapWithPath(e, chunk, buffer.bufferedSize() + ix);
274 }
275
276 Object[] result;
277
278 if (_untyped) {
279 result = buffer.completeAndClearBuffer(chunk, ix);
280 } else {
281 result = buffer.completeAndClearBuffer(chunk, ix, _elementClass);
282 }
283 ctxt.returnObjectBuffer(buffer);
284 return result;
285 }
286
287
292
293 protected Byte[] deserializeFromBase64(JsonParser p, DeserializationContext ctxt)
294 throws IOException
295 {
296
297 byte[] b = p.getBinaryValue(ctxt.getBase64Variant());
298
299 Byte[] result = new Byte[b.length];
300 for (int i = 0, len = b.length; i < len; ++i) {
301 result[i] = Byte.valueOf(b[i]);
302 }
303 return result;
304 }
305
306 protected Object[] handleNonArray(JsonParser p, DeserializationContext ctxt)
307 throws IOException
308 {
309
310 if (p.hasToken(JsonToken.VALUE_STRING)
311 && ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)) {
312 String str = p.getText();
313 if (str.length() == 0) {
314 return null;
315 }
316 }
317
318
319 boolean canWrap = (_unwrapSingle == Boolean.TRUE) ||
320 ((_unwrapSingle == null) &&
321 ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
322 if (!canWrap) {
323
324 if (p.hasToken(JsonToken.VALUE_STRING)
325
326 && _elementClass == Byte.class) {
327 return deserializeFromBase64(p, ctxt);
328 }
329 return (Object[]) ctxt.handleUnexpectedToken(_containerType.getRawClass(), p);
330 }
331
332 Object value;
333 if (p.hasToken(JsonToken.VALUE_NULL)) {
334
335 if (_skipNullValues) {
336 return NO_OBJECTS;
337 }
338 value = _nullProvider.getNullValue(ctxt);
339 } else if (_elementTypeDeserializer == null) {
340 value = _elementDeserializer.deserialize(p, ctxt);
341 } else {
342 value = _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer);
343 }
344
345 Object[] result;
346
347 if (_untyped) {
348 result = new Object[1];
349 } else {
350 result = (Object[]) Array.newInstance(_elementClass, 1);
351 }
352 result[0] = value;
353 return result;
354 }
355 }
356
357