package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.NullValueProvider;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.AccessPattern;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* Intermediate base deserializer class that adds more shared accessor
* so that other classes can access information about contained (value) types
*/
@SuppressWarnings("serial")
public abstract class ContainerDeserializerBase<T>
extends StdDeserializer<T>
implements ValueInstantiator.Gettable // since 2.9
{
protected final JavaType _containerType;
/**
* Handler we need for dealing with nulls.
*
* @since 2.9
*/
protected final NullValueProvider _nullProvider;
/**
* Specific override for this instance (from proper, or global per-type overrides)
* to indicate whether single value may be taken to mean an unwrapped one-element array
* or not. If null, left to global defaults.
*
* @since 2.9 (demoted from sub-classes where added in 2.7)
*/
protected final Boolean _unwrapSingle;
/**
* Marker flag set if the <code>_nullProvider</code> indicates that all null
* content values should be skipped (instead of being possibly converted).
*
* @since 2.9
*/
protected final boolean _skipNullValues;
protected ContainerDeserializerBase(JavaType selfType,
NullValueProvider nuller, Boolean unwrapSingle) {
super(selfType);
_containerType = selfType;
_unwrapSingle = unwrapSingle;
_nullProvider = nuller;
_skipNullValues = NullsConstantProvider.isSkipper(nuller);
}
protected ContainerDeserializerBase(JavaType selfType) {
this(selfType, null, null);
}
/**
* @since 2.9
*/
protected ContainerDeserializerBase(ContainerDeserializerBase<?> base) {
this(base, base._nullProvider, base._unwrapSingle);
}
/**
* @since 2.9
*/
protected ContainerDeserializerBase(ContainerDeserializerBase<?> base,
NullValueProvider nuller, Boolean unwrapSingle) {
super(base._containerType);
_containerType = base._containerType;
_nullProvider = nuller;
_unwrapSingle = unwrapSingle;
_skipNullValues = NullsConstantProvider.isSkipper(nuller);
}
/*
/**********************************************************
/* Overrides
/**********************************************************
*/
@Override // since 2.9
public JavaType getValueType() { return _containerType; }
@Override // since 2.9
public Boolean supportsUpdate(DeserializationConfig config) {
return Boolean.TRUE;
}
@Override
public SettableBeanProperty findBackReference(String refName) {
JsonDeserializer<Object> valueDeser = getContentDeserializer();
if (valueDeser == null) {
throw new IllegalArgumentException(String.format(
"Can not handle managed/back reference '%s': type: container deserializer of type %s returned null for 'getContentDeserializer()'",
refName, getClass().getName()));
}
return valueDeser.findBackReference(refName);
}
/*
/**********************************************************
/* Extended API
/**********************************************************
*/
/**
* Accessor for declared type of contained value elements; either exact
* type, or one of its supertypes.
*/
public JavaType getContentType() {
if (_containerType == null) {
return TypeFactory.unknownType(); // should never occur but...
}
return _containerType.getContentType();
}
/**
* Accesor for deserializer use for deserializing content values.
*/
public abstract JsonDeserializer<Object> getContentDeserializer();
/**
* @since 2.9
*/
@Override
public ValueInstantiator getValueInstantiator() {
return null;
}
@Override // since 2.9
public AccessPattern getEmptyAccessPattern() {
// 02-Feb-2017, tatu: Empty containers are usually constructed as needed
// and may not be shared; for some deserializers this may be further refined.
return AccessPattern.DYNAMIC;
}
@Override // since 2.9
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
ValueInstantiator vi = getValueInstantiator();
if (vi == null || !vi.canCreateUsingDefault()) {
JavaType type = getValueType();
ctxt.reportBadDefinition(type,
String.format("Can not create empty instance of %s, no default Creator", type));
}
try {
return vi.createUsingDefault(ctxt);
} catch (IOException e) {
return ClassUtil.throwAsMappingException(ctxt, e);
}
}
/*
/**********************************************************
/* Shared methods for sub-classes
/**********************************************************
*/
/**
* Helper method called by various Map(-like) deserializers.
*/
protected <BOGUS> BOGUS wrapAndThrow(Throwable t, Object ref, String key) throws IOException
{
// to handle StackOverflow:
while (t instanceof InvocationTargetException && t.getCause() != null) {
t = t.getCause();
}
// Errors and "plain" IOExceptions to be passed as is
ClassUtil.throwIfError(t);
// ... except for mapping exceptions
if (t instanceof IOException && !(t instanceof JsonMappingException)) {
throw (IOException) t;
}
// for [databind#1141]
throw JsonMappingException.wrapWithPath(t, ref,
ClassUtil.nonNull(key, "N/A"));
}
}