package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.NullValueProvider;
import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.type.LogicalType;
import com.fasterxml.jackson.databind.util.AccessPattern;
import com.fasterxml.jackson.databind.util.ObjectBuffer;
@JacksonStdImpl
public final class StringArrayDeserializer
extends StdDeserializer<String[]>
implements ContextualDeserializer
{
private static final long serialVersionUID = 2L;
private final static String[] NO_STRINGS = new String[0];
public final static StringArrayDeserializer instance = new StringArrayDeserializer();
protected JsonDeserializer<String> _elementDeserializer;
protected final NullValueProvider _nullProvider;
protected final Boolean _unwrapSingle;
protected final boolean _skipNullValues;
public StringArrayDeserializer() {
this(null, null, null);
}
@SuppressWarnings("unchecked")
protected StringArrayDeserializer(JsonDeserializer<?> deser,
NullValueProvider nuller, Boolean unwrapSingle) {
super(String[].class);
_elementDeserializer = (JsonDeserializer<String>) deser;
_nullProvider = nuller;
_unwrapSingle = unwrapSingle;
_skipNullValues = NullsConstantProvider.isSkipper(nuller);
}
@Override
public LogicalType logicalType() {
return LogicalType.Array;
}
@Override
public Boolean supportsUpdate(DeserializationConfig config) {
return Boolean.TRUE;
}
@Override
public AccessPattern getEmptyAccessPattern() {
return AccessPattern.CONSTANT;
}
@Override
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
return NO_STRINGS;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException
{
JsonDeserializer<?> deser = _elementDeserializer;
deser = findConvertingContentDeserializer(ctxt, property, deser);
JavaType type = ctxt.constructType(String.class);
if (deser == null) {
deser = ctxt.findContextualValueDeserializer(type, property);
} else {
deser = ctxt.handleSecondaryContextualization(deser, property, type);
}
Boolean unwrapSingle = findFormatFeature(ctxt, property, String[].class,
JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
NullValueProvider nuller = findContentNullProvider(ctxt, property, deser);
if ((deser != null) && isDefaultDeserializer(deser)) {
deser = null;
}
if ((_elementDeserializer == deser)
&& (Objects.equals(_unwrapSingle, unwrapSingle))
&& (_nullProvider == nuller)) {
return this;
}
return new StringArrayDeserializer(deser, nuller, unwrapSingle);
}
@Override
public String[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (!p.isExpectedStartArrayToken()) {
return handleNonArray(p, ctxt);
}
if (_elementDeserializer != null) {
return _deserializeCustom(p, ctxt, null);
}
final ObjectBuffer buffer = ctxt.leaseObjectBuffer();
Object[] chunk = buffer.resetAndStart();
int ix = 0;
try {
while (true) {
String value = p.nextTextValue();
if (value == null) {
JsonToken t = p.currentToken();
if (t == JsonToken.END_ARRAY) {
break;
}
if (t == JsonToken.VALUE_NULL) {
if (_skipNullValues) {
continue;
}
value = (String) _nullProvider.getNullValue(ctxt);
} else {
value = _parseString(p, ctxt);
}
}
if (ix >= chunk.length) {
chunk = buffer.appendCompletedChunk(chunk);
ix = 0;
}
chunk[ix++] = value;
}
} catch (Exception e) {
throw JsonMappingException.wrapWithPath(e, chunk, buffer.bufferedSize() + ix);
}
String[] result = buffer.completeAndClearBuffer(chunk, ix, String.class);
ctxt.returnObjectBuffer(buffer);
return result;
}
protected final String[] _deserializeCustom(JsonParser p, DeserializationContext ctxt,
String[] old) throws IOException
{
final ObjectBuffer buffer = ctxt.leaseObjectBuffer();
int ix;
Object[] chunk;
if (old == null) {
ix = 0;
chunk = buffer.resetAndStart();
} else {
ix = old.length;
chunk = buffer.resetAndStart(old, ix);
}
final JsonDeserializer<String> deser = _elementDeserializer;
try {
while (true) {
String value;
if (p.nextTextValue() == null) {
JsonToken t = p.currentToken();
if (t == JsonToken.END_ARRAY) {
break;
}
if (t == JsonToken.VALUE_NULL) {
if (_skipNullValues) {
continue;
}
value = (String) _nullProvider.getNullValue(ctxt);
} else {
value = deser.deserialize(p, ctxt);
}
} else {
value = deser.deserialize(p, ctxt);
}
if (ix >= chunk.length) {
chunk = buffer.appendCompletedChunk(chunk);
ix = 0;
}
chunk[ix++] = value;
}
} catch (Exception e) {
throw JsonMappingException.wrapWithPath(e, String.class, ix);
}
String[] result = buffer.completeAndClearBuffer(chunk, ix, String.class);
ctxt.returnObjectBuffer(buffer);
return result;
}
@Override
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException {
return typeDeserializer.deserializeTypedFromArray(p, ctxt);
}
@Override
public String[] deserialize(JsonParser p, DeserializationContext ctxt,
String[] intoValue) throws IOException
{
if (!p.isExpectedStartArrayToken()) {
String[] arr = handleNonArray(p, ctxt);
if (arr == null) {
return intoValue;
}
final int offset = intoValue.length;
String[] result = new String[offset + arr.length];
System.arraycopy(intoValue, 0, result, 0, offset);
System.arraycopy(arr, 0, result, offset, arr.length);
return result;
}
if (_elementDeserializer != null) {
return _deserializeCustom(p, ctxt, intoValue);
}
final ObjectBuffer buffer = ctxt.leaseObjectBuffer();
int ix = intoValue.length;
Object[] chunk = buffer.resetAndStart(intoValue, ix);
try {
while (true) {
String value = p.nextTextValue();
if (value == null) {
JsonToken t = p.currentToken();
if (t == JsonToken.END_ARRAY) {
break;
}
if (t == JsonToken.VALUE_NULL) {
if (_skipNullValues) {
return NO_STRINGS;
}
value = (String) _nullProvider.getNullValue(ctxt);
} else {
value = _parseString(p, ctxt);
}
}
if (ix >= chunk.length) {
chunk = buffer.appendCompletedChunk(chunk);
ix = 0;
}
chunk[ix++] = value;
}
} catch (Exception e) {
throw JsonMappingException.wrapWithPath(e, chunk, buffer.bufferedSize() + ix);
}
String[] result = buffer.completeAndClearBuffer(chunk, ix, String.class);
ctxt.returnObjectBuffer(buffer);
return result;
}
private final String[] handleNonArray(JsonParser p, DeserializationContext ctxt) throws IOException
{
boolean canWrap = (_unwrapSingle == Boolean.TRUE) ||
((_unwrapSingle == null) &&
ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
if (canWrap) {
String value = p.hasToken(JsonToken.VALUE_NULL)
? (String) _nullProvider.getNullValue(ctxt)
: _parseString(p, ctxt);
return new String[] { value };
}
if (p.hasToken(JsonToken.VALUE_STRING)) {
return _deserializeFromString(p, ctxt);
}
return (String[]) ctxt.handleUnexpectedToken(_valueClass, p);
}
}