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

com.fasterxml.jackson.databind.deser.std.CollectionDeserializer Maven / Gradle / Ivy

There is a newer version: 2.22.2
Show newest version
package com.fasterxml.jackson.databind.deser.std;

import java.io.IOException;
import java.util.*;

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.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;

/**
 * Basic serializer that can take JSON "Array" structure and
 * construct a {@link java.util.Collection} instance, with typed contents.
 *

* Note: for untyped content (one indicated by passing Object.class * as the type), {@link UntypedObjectDeserializer} is used instead. * It can also construct {@link java.util.List}s, but not with specific * POJO types, only other containers and primitives/wrappers. */ @JacksonStdImpl public class CollectionDeserializer extends ContainerDeserializerBase> implements ContextualDeserializer { private static final long serialVersionUID = -2003828398549708958L; // // Configuration protected final JavaType _collectionType; /** * Value deserializer. */ protected final JsonDeserializer _valueDeserializer; /** * If element instances have polymorphic type information, this * is the type deserializer that can handle it */ protected final TypeDeserializer _valueTypeDeserializer; // // Instance construction settings: protected final ValueInstantiator _valueInstantiator; /** * Deserializer that is used iff delegate-based creator is * to be used for deserializing from JSON Object. */ protected final JsonDeserializer _delegateDeserializer; // NOTE: no PropertyBasedCreator, as JSON Arrays have no properties /* /********************************************************** /* Life-cycle /********************************************************** */ /** * Constructor for context-free instances, where we do not yet know * which property is using this deserializer. */ public CollectionDeserializer(JavaType collectionType, JsonDeserializer valueDeser, TypeDeserializer valueTypeDeser, ValueInstantiator valueInstantiator) { this(collectionType, valueDeser, valueTypeDeser, valueInstantiator, null); } /** * Constructor used when creating contextualized instances. */ protected CollectionDeserializer(JavaType collectionType, JsonDeserializer valueDeser, TypeDeserializer valueTypeDeser, ValueInstantiator valueInstantiator, JsonDeserializer delegateDeser) { super(collectionType); _collectionType = collectionType; _valueDeserializer = valueDeser; _valueTypeDeserializer = valueTypeDeser; _valueInstantiator = valueInstantiator; _delegateDeserializer = delegateDeser; } /** * Copy-constructor that can be used by sub-classes to allow * copy-on-write styling copying of settings of an existing instance. */ protected CollectionDeserializer(CollectionDeserializer src) { super(src._collectionType); _collectionType = src._collectionType; _valueDeserializer = src._valueDeserializer; _valueTypeDeserializer = src._valueTypeDeserializer; _valueInstantiator = src._valueInstantiator; _delegateDeserializer = src._delegateDeserializer; } /** * Fluent-factory method call to construct contextual instance. */ @SuppressWarnings("unchecked") protected CollectionDeserializer withResolved(JsonDeserializer dd, JsonDeserializer vd, TypeDeserializer vtd) { if ((dd == _delegateDeserializer) && (vd == _valueDeserializer) && (vtd == _valueTypeDeserializer)) { return this; } return new CollectionDeserializer(_collectionType, (JsonDeserializer) vd, vtd, _valueInstantiator, (JsonDeserializer) dd); } /* /********************************************************** /* Validation, post-processing (ResolvableDeserializer) /********************************************************** */ /** * Method called to finalize setup of this deserializer, * when it is known for which property deserializer is needed * for. */ @Override public CollectionDeserializer createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { // May need to resolve types for delegate-based creators: JsonDeserializer delegateDeser = null; if ((_valueInstantiator != null) && _valueInstantiator.canCreateUsingDelegate()) { JavaType delegateType = _valueInstantiator.getDelegateType(ctxt.getConfig()); if (delegateType == null) { throw new IllegalArgumentException("Invalid delegate-creator definition for "+_collectionType +": value instantiator ("+_valueInstantiator.getClass().getName() +") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'"); } delegateDeser = findDeserializer(ctxt, delegateType, property); } // also, often value deserializer is resolved here: JsonDeserializer valueDeser = _valueDeserializer; // #125: May have a content converter valueDeser = findConvertingContentDeserializer(ctxt, property, valueDeser); if (valueDeser == null) { valueDeser = ctxt.findContextualValueDeserializer( _collectionType.getContentType(), property); } else { // if directly assigned, probably not yet contextual, so: valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property); } // and finally, type deserializer needs context as well TypeDeserializer valueTypeDeser = _valueTypeDeserializer; if (valueTypeDeser != null) { valueTypeDeser = valueTypeDeser.forProperty(property); } return withResolved(delegateDeser, valueDeser, valueTypeDeser); } /* /********************************************************** /* ContainerDeserializerBase API /********************************************************** */ @Override public JavaType getContentType() { return _collectionType.getContentType(); } @Override public JsonDeserializer getContentDeserializer() { return _valueDeserializer; } /* /********************************************************** /* JsonDeserializer API /********************************************************** */ @SuppressWarnings("unchecked") @Override public Collection deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { if (_delegateDeserializer != null) { return (Collection) _valueInstantiator.createUsingDelegate(ctxt, _delegateDeserializer.deserialize(jp, ctxt)); } /* [JACKSON-620]: empty String may be ok; bit tricky to check, however, since * there is also possibility of "auto-wrapping" of single-element arrays. * Hence we only accept empty String here. */ if (jp.getCurrentToken() == JsonToken.VALUE_STRING) { String str = jp.getText(); if (str.length() == 0) { return (Collection) _valueInstantiator.createFromString(ctxt, str); } } return deserialize(jp, ctxt, (Collection) _valueInstantiator.createUsingDefault(ctxt)); } @Override public Collection deserialize(JsonParser jp, DeserializationContext ctxt, Collection result) throws IOException, JsonProcessingException { // Ok: must point to START_ARRAY (or equivalent) if (!jp.isExpectedStartArrayToken()) { return handleNonArray(jp, ctxt, result); } JsonDeserializer valueDes = _valueDeserializer; JsonToken t; final TypeDeserializer typeDeser = _valueTypeDeserializer; while ((t = jp.nextToken()) != JsonToken.END_ARRAY) { Object value; if (t == JsonToken.VALUE_NULL) { value = null; } else if (typeDeser == null) { value = valueDes.deserialize(jp, ctxt); } else { value = valueDes.deserializeWithType(jp, ctxt, typeDeser); } result.add(value); } return result; } @Override public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JsonProcessingException { // In future could check current token... for now this should be enough: return typeDeserializer.deserializeTypedFromArray(jp, ctxt); } /** * Helper method called when current token is no START_ARRAY. Will either * throw an exception, or try to handle value as if member of implicit * array, depending on configuration. */ protected final Collection handleNonArray(JsonParser jp, DeserializationContext ctxt, Collection result) throws IOException, JsonProcessingException { // [JACKSON-526]: implicit arrays from single values? if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)) { throw ctxt.mappingException(_collectionType.getRawClass()); } JsonDeserializer valueDes = _valueDeserializer; final TypeDeserializer typeDeser = _valueTypeDeserializer; JsonToken t = jp.getCurrentToken(); Object value; if (t == JsonToken.VALUE_NULL) { value = null; } else if (typeDeser == null) { value = valueDes.deserialize(jp, ctxt); } else { value = valueDes.deserializeWithType(jp, ctxt, typeDeser); } result.add(value); return result; } }