All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.prestosql.jdbc.$internal.jackson.datatype.guava.deser.GuavaCollectionDeserializer Maven / Gradle / Ivy

There is a newer version: 350
Show newest version
package io.prestosql.jdbc.$internal.jackson.datatype.guava.deser;

import java.io.IOException;
import java.util.Collection;

import io.prestosql.jdbc.$internal.jackson.annotation.JsonFormat;
import io.prestosql.jdbc.$internal.jackson.core.*;
import io.prestosql.jdbc.$internal.jackson.databind.*;
import io.prestosql.jdbc.$internal.jackson.databind.deser.ContextualDeserializer;
import io.prestosql.jdbc.$internal.jackson.databind.deser.NullValueProvider;
import io.prestosql.jdbc.$internal.jackson.databind.deser.std.ContainerDeserializerBase;
import io.prestosql.jdbc.$internal.jackson.databind.jsontype.TypeDeserializer;
import io.prestosql.jdbc.$internal.jackson.databind.util.AccessPattern;

/**
 * Base class for Guava-specific collection deserializers.
 */
public abstract class GuavaCollectionDeserializer
    extends ContainerDeserializerBase
    implements ContextualDeserializer
{
    private static final long serialVersionUID = 1L;

    /**
     * Deserializer used for values contained in collection being deserialized;
     * either assigned on constructor, or during resolve().
     */
    protected final JsonDeserializer _valueDeserializer;

    /**
     * If value instances have polymorphic type information, this
     * is the type deserializer that can deserialize required type
     * information
     */
    protected final TypeDeserializer _valueTypeDeserializer;

    /*
    /**********************************************************
    /* Life-cycle
    /**********************************************************
     */

    protected GuavaCollectionDeserializer(JavaType selfType,
            JsonDeserializer deser, TypeDeserializer typeDeser,
            NullValueProvider nuller, Boolean unwrapSingle)
    {
        super(selfType, nuller, unwrapSingle);
        _valueTypeDeserializer = typeDeser;
        _valueDeserializer = deser;
    }

    /**
     * Overridable fluent factory method used for creating contextual
     * instances.
     */
    public abstract GuavaCollectionDeserializer withResolved(
            JsonDeserializer valueDeser, TypeDeserializer typeDeser, 
            NullValueProvider nuller, Boolean unwrapSingle);

    /**
     * Method called to finalize setup of this deserializer,
     * after deserializer itself has been registered. This
     * is needed to handle recursive and transitive dependencies.
     */
    @Override
    public JsonDeserializer createContextual(DeserializationContext ctxt,
            BeanProperty property) throws JsonMappingException
    {
        Boolean unwrapSingle = findFormatFeature(ctxt, property, Collection.class,
                JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

        JsonDeserializer valueDeser = _valueDeserializer;
        TypeDeserializer valueTypeDeser = _valueTypeDeserializer;
        if (valueDeser == null) {
            valueDeser = ctxt.findContextualValueDeserializer(_containerType.getContentType(), property);
        }
        if (valueTypeDeser != null) {
            valueTypeDeser = valueTypeDeser.forProperty(property);
        }

        NullValueProvider nuller = findContentNullProvider(ctxt, property, valueDeser);

        if ( (unwrapSingle != _unwrapSingle)
                || (nuller != _nullProvider)
                || (valueDeser != _valueDeserializer)
                || (valueTypeDeser != _valueTypeDeserializer)) {
            return withResolved(valueDeser, valueTypeDeser, nuller, unwrapSingle);
        }
        return this;
    }

    /*
    /**********************************************************
    /* Base class method implementations
    /**********************************************************
     */

    @SuppressWarnings("unchecked")
    @Override
    public JsonDeserializer getContentDeserializer() {
        return (JsonDeserializer) _valueDeserializer;
    }

    /*
    /**********************************************************
    /* Deserialization interface
    /**********************************************************
     */

    /**
     * Base implementation that does not assume specific type
     * inclusion mechanism. Sub-classes are expected to override
     * this method if they are to handle type information.
     */
    @Override
    public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
            TypeDeserializer typeDeserializer)
        throws IOException
    {
        return typeDeserializer.deserializeTypedFromArray(p, ctxt);
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException
    {
        // Should usually point to START_ARRAY
        if (p.isExpectedStartArrayToken()) {
            return _deserializeContents(p, ctxt);
        }
        // But may support implicit arrays from single values?
        if (ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)) {
            return _deserializeFromSingleValue(p, ctxt);
        }
        return (T) ctxt.handleUnexpectedToken(_valueClass, p);
    }

    /*
    /**********************************************************************
    /* Abstract methods for impl classes
    /**********************************************************************
     */

    // Force abstract-ness for subclasses
    @Override
    public abstract AccessPattern getEmptyAccessPattern();

    // Force abstract-ness for subclasses
    @Override
    public abstract Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException;

    protected abstract T _deserializeContents(JsonParser p, DeserializationContext ctxt)
            throws IOException;

    /**
     * Method used to support implicit coercion from a single non-array value
     * into single-element collection.
     * 
     * @since 2.3
     */
    protected T _deserializeFromSingleValue(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException
    {
        final JsonDeserializer valueDes = _valueDeserializer;
        final TypeDeserializer typeDeser = _valueTypeDeserializer;
        final JsonToken t = p.getCurrentToken();

        final Object value;

        if (t == JsonToken.VALUE_NULL) {
            if (_skipNullValues) {
                return _createEmpty(ctxt);
            }
            value = _nullProvider.getNullValue(ctxt);
        } else if (typeDeser == null) {
            value = valueDes.deserialize(p, ctxt);
        } else {
            value = valueDes.deserializeWithType(p, ctxt, typeDeser);
        }
        return _createWithSingleElement(ctxt, value);

    }

    // Note: 'throws IOException' dropped from 2.10.5
    protected abstract T _createEmpty(DeserializationContext ctxt);

    protected abstract T _createWithSingleElement(DeserializationContext ctxt, Object value) throws IOException;
}