Skip to content

Commit

Permalink
Implemented #165: Add DeserializationContext.getContextualType() wh…
Browse files Browse the repository at this point in the history
…ich can be called by contextual deserializers to know nominal type for them, without needing to decipher it from `BeanProperty`
  • Loading branch information
cowtowncoder committed Dec 27, 2014
1 parent 53d4c4c commit c4b6c61
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 47 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project: jackson-databind

#47: Support `@JsonValue` for (Map) key serialization
#113: Problem deserializing polymorphic types with @JsonCreator
#165: Add `DeserializationContext.getContextualType()` to let deserializer
known the expected type.
#408: External type id does not allow use of 'visible=true'
#421: @JsonCreator not used in case of multiple creators with parameter names
(reported by Lovro P, lpandzic@github)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ public abstract class DeserializationContext
* @since 2.3
*/
protected transient ContextAttributes _attributes;

/**
* Type of {@link JsonDeserializer} (or, more specifically,
* {@link ContextualizableDeserializer}) that is being
* contextualized currently.
*
* @since 2.5
*/
protected LinkedNode<JavaType> _currentType;

/*
/**********************************************************
Expand Down Expand Up @@ -224,7 +233,7 @@ public final TypeFactory getTypeFactory() {

/*
/**********************************************************
/* Generic attributes (2.3+)
/* Access to per-call state, like generic attributes (2.3+)
/**********************************************************
*/

Expand All @@ -239,10 +248,27 @@ public DeserializationContext setAttribute(Object key, Object value)
_attributes = _attributes.withPerCallAttribute(key, value);
return this;
}


/**
* Accessor to {@link JavaType} of currently contextualized
* {@link ContextualDeserializer}, if any.
* This is sometimes useful for generic {@link JsonDeserializer}s that
* do not get passed (or do not retain) type information when being
* constructed: happens for example for deserializers constructed
* from annotations.
*
* @since 2.5
*
* @return Type of {@link ContextualDeserializer} being contextualized,
* if process is on-going; null if not.
*/
public JavaType getContextualType() {
return (_currentType == null) ? null : _currentType.value();
}

/*
/**********************************************************
/* Public API, accessors
/* Public API, config setting accessors
/**********************************************************
*/

Expand Down Expand Up @@ -379,7 +405,7 @@ public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType t
{
JsonDeserializer<Object> deser = _cache.findValueDeserializer(this, _factory, type);
if (deser != null) {
deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop);
deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, prop, type);
}
return deser;
}
Expand All @@ -391,8 +417,8 @@ public final JsonDeserializer<Object> findContextualValueDeserializer(JavaType t
* {@link #findRootValueDeserializer(JavaType)}.
* This method is usually called from within {@link ResolvableDeserializer#resolve},
* and expectation is that caller then calls either
* {@link #handlePrimaryContextualization(JsonDeserializer, BeanProperty)} or
* {@link #handleSecondaryContextualization(JsonDeserializer, BeanProperty)} at a
* {@link #handlePrimaryContextualization(JsonDeserializer, BeanProperty, JavaType)} or
* {@link #handleSecondaryContextualization(JsonDeserializer, BeanProperty, JavaType)} at a
* later point, as necessary.
*
* @since 2.5
Expand All @@ -415,7 +441,7 @@ public final JsonDeserializer<Object> findRootValueDeserializer(JavaType type)
if (deser == null) { // can this occur?
return null;
}
deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null);
deser = (JsonDeserializer<Object>) handleSecondaryContextualization(deser, null, type);
TypeDeserializer typeDeser = _factory.findTypeDeserializer(_config, type);
if (typeDeser != null) {
// important: contextualize to indicate this is for root value
Expand Down Expand Up @@ -576,18 +602,31 @@ public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
*
* @param prop Property for which the given primary deserializer is used; never null.
*
* @since 2.3
* @since 2.5
*/
public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
BeanProperty prop)
BeanProperty prop, JavaType type)
throws JsonMappingException
{
if (deser instanceof ContextualDeserializer) {
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
_currentType = new LinkedNode<JavaType>(type, _currentType);
try {
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
} finally {
_currentType = _currentType.next();
}
}
return deser;
}

@Deprecated // since 2.5; remove from 2.6
public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
BeanProperty prop)
throws JsonMappingException
{
return handlePrimaryContextualization(deser, prop, TypeFactory.unknownType());
}

/**
* Method called for secondary property deserializers (ones
* NOT directly created to deal with an annotatable POJO property,
Expand All @@ -602,8 +641,24 @@ public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> de
* @param prop Property for which deserializer is used, if any; null
* when deserializing root values
*
* @since 2.3
* @since 2.5
*/
public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
BeanProperty prop, JavaType type)
throws JsonMappingException
{
if (deser instanceof ContextualDeserializer) {
_currentType = new LinkedNode<JavaType>(type, _currentType);
try {
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
} finally {
_currentType = _currentType.next();
}
}
return deser;
}

@Deprecated // since 2.5; remove from 2.6
public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
BeanProperty prop)
throws JsonMappingException
Expand All @@ -613,7 +668,7 @@ public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?>
}
return deser;
}

/*
/**********************************************************
/* Parsing methods that may use reusable/-cyclable objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ protected CreatorProperty constructCreatorProperty(DeserializationContext ctxt,
metadata);
if (deser != null) {
// As per [Issue#462] need to ensure we contextualize deserializer before passing it on
deser = ctxt.handlePrimaryContextualization(deser, prop);
deser = ctxt.handlePrimaryContextualization(deser, prop, type);
prop = prop.withValueDeserializer(deser);
}
return prop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,8 @@ public void resolve(DeserializationContext ctxt)
/* Important! This is the only place where actually handle "primary"
* property deserializers -- call is different from other places.
*/
JsonDeserializer<?> cd = ctxt.handlePrimaryContextualization(deser, prop);
JsonDeserializer<?> cd = ctxt.handlePrimaryContextualization(deser, prop,
prop.getType());
if (cd != deser) {
prop = prop.withValueDeserializer(cd);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ public CollectionDeserializer createContextual(DeserializationContext ctxt,
JsonDeserializer<?> valueDeser = _valueDeserializer;
// #125: May have a content converter
valueDeser = findConvertingContentDeserializer(ctxt, property, valueDeser);
final JavaType vt = _collectionType.getContentType();
if (valueDeser == null) {
valueDeser = ctxt.findContextualValueDeserializer(
_collectionType.getContentType(), property);
valueDeser = ctxt.findContextualValueDeserializer(vt, property);
} else { // if directly assigned, probably not yet contextual, so:
valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property);
valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property, vt);
}
// and finally, type deserializer needs context as well
TypeDeserializer valueTypeDeser = _valueTypeDeserializer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property)
throws JsonMappingException
{
JsonDeserializer<?> del = ctxt.handleSecondaryContextualization(_delegatee, property);
JavaType vt = ctxt.constructType(_delegatee.handledType());
JsonDeserializer<?> del = ctxt.handleSecondaryContextualization(_delegatee,
property, vt);
if (del == _delegatee) {
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanPro
kd = ctxt.findKeyDeserializer(_mapType.getKeyType(), property);
}
JsonDeserializer<?> vd = _valueDeserializer;
final JavaType vt = _mapType.getContentType();
if (vd == null) {
vd = ctxt.findContextualValueDeserializer(_mapType.getContentType(), property);
vd = ctxt.findContextualValueDeserializer(vt, property);
} else { // if directly assigned, probably not yet contextual, so:
vd = ctxt.handleSecondaryContextualization(vd, property);
vd = ctxt.handleSecondaryContextualization(vd, property, vt);
}
TypeDeserializer vtd = _valueTypeDeserializer;
if (vtd != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
if (deser == null) {
deser = ctxt.findContextualValueDeserializer(_enumType, property);
} else { // if directly assigned, probably not yet contextual, so:
deser = ctxt.handleSecondaryContextualization(deser, property);
deser = ctxt.handleSecondaryContextualization(deser, property, _enumType);
}
return withDeserializer(deser);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
JsonDeserializer<?> vd = _valueDeserializer;
// #125: May have a content converter
vd = findConvertingContentDeserializer(ctxt, property, vd);
final JavaType vt = _mapType.getContentType();
if (vd == null) {
vd = ctxt.findContextualValueDeserializer(_mapType.getContentType(), property);
vd = ctxt.findContextualValueDeserializer(vt, property);
} else { // if directly assigned, probably not yet contextual, so:
vd = ctxt.handleSecondaryContextualization(vd, property);
vd = ctxt.handleSecondaryContextualization(vd, property, vt);
}
TypeDeserializer vtd = _valueTypeDeserializer;
if (vtd != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
}
JsonDeserializer<?> vd = _valueDeserializer;
vd = findConvertingContentDeserializer(ctxt, property, vd);
JavaType contentType = _type.containedType(1);
if (vd == null) {
vd = ctxt.findContextualValueDeserializer(_type.containedType(1), property);
vd = ctxt.findContextualValueDeserializer(contentType, property);
} else { // if directly assigned, probably not yet contextual, so:
vd = ctxt.handleSecondaryContextualization(vd, property);
vd = ctxt.handleSecondaryContextualization(vd, property, contentType);
}
TypeDeserializer vtd = _valueTypeDeserializer;
if (vtd != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
JsonDeserializer<?> deser = _elementDeserializer;
// #125: May have a content converter
deser = findConvertingContentDeserializer(ctxt, property, deser);
final JavaType vt = _arrayType.getContentType();
if (deser == null) {
deser = ctxt.findContextualValueDeserializer(_arrayType.getContentType(), property);
deser = ctxt.findContextualValueDeserializer(vt, property);
} else { // if directly assigned, probably not yet contextual, so:
deser = ctxt.handleSecondaryContextualization(deser, property);
deser = ctxt.handleSecondaryContextualization(deser, property, vt);
}
TypeDeserializer elemTypeDeser = _elementTypeDeserializer;
if (elemTypeDeser != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanPro
{
// First: if already got serializer to delegate to, contextualize it:
if (_delegateDeserializer != null) {
JsonDeserializer<?> deser = ctxt.handleSecondaryContextualization(_delegateDeserializer, property);
JsonDeserializer<?> deser = ctxt.handleSecondaryContextualization(_delegateDeserializer,
property, _delegateType);
if (deser != _delegateDeserializer) {
return withDelegate(_converter, _delegateType, deser);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanPro
JsonDeserializer<?> deser = _elementDeserializer;
// #125: May have a content converter
deser = findConvertingContentDeserializer(ctxt, property, deser);
JavaType type = ctxt.constructType(String.class);
if (deser == null) {
deser = ctxt.findContextualValueDeserializer(ctxt.constructType(String.class), property);
deser = ctxt.findContextualValueDeserializer(type, property);
} else { // if directly assigned, probably not yet contextual, so:
deser = ctxt.handleSecondaryContextualization(deser, property);
deser = ctxt.handleSecondaryContextualization(deser, property, type);
}
// Ok ok: if all we got is the default String deserializer, can just forget about it
if (deser != null && this.isDefaultDeserializer(deser)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,16 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
}
}
JsonDeserializer<?> valueDeser = _valueDeserializer;
final JavaType valueType = _collectionType.getContentType();
if (valueDeser == null) {
// #125: May have a content converter
valueDeser = findConvertingContentDeserializer(ctxt, property, valueDeser);
if (valueDeser == null) {
// And we may also need to get deserializer for String
valueDeser = ctxt.findContextualValueDeserializer( _collectionType.getContentType(), property);
valueDeser = ctxt.findContextualValueDeserializer(valueType, property);
}
} else { // if directly assigned, probably not yet contextual, so:
valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property);
valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property, valueType);
}
if (isDefaultDeserializer(valueDeser)) {
valueDeser = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,11 @@ public void resolve(DeserializationContext ctxt) throws JsonMappingException

// and then do bogus contextualization, in case custom ones need to resolve dependencies of
// their own
_mapDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_mapDeserializer, null);
_listDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_listDeserializer, null);
_stringDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_stringDeserializer, null);
_numberDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_numberDeserializer, null);
JavaType unknown = TypeFactory.unknownType();
_mapDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_mapDeserializer, null, unknown);
_listDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_listDeserializer, null, unknown);
_stringDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_stringDeserializer, null, unknown);
_numberDeserializer = (JsonDeserializer<Object>) ctxt.handleSecondaryContextualization(_numberDeserializer, null, unknown);
}

@SuppressWarnings("unchecked")
Expand Down
Loading

0 comments on commit c4b6c61

Please sign in to comment.