Skip to content

Commit

Permalink
Completed type/property handling cleanup: should work as well as or b…
Browse files Browse the repository at this point in the history
…etter than previously, wrt. contextualization
  • Loading branch information
cowtowncoder committed Jun 19, 2016
1 parent cbb558d commit feb8293
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 72 deletions.
Expand Up @@ -837,14 +837,10 @@ protected SettableBeanProperty constructCreatorProperty(DeserializationContext c
metadata = PropertyMetadata.construct(req, desc, idx, def); metadata = PropertyMetadata.construct(req, desc, idx, def);
} }
} }
JavaType type = param.getType(); JavaType type = resolveMemberAndTypeAnnotations(ctxt, param, param.getType());
type = resolveMemberAndTypeAnnotations(ctxt, type, param);
BeanProperty.Std property = new BeanProperty.Std(name, type, BeanProperty.Std property = new BeanProperty.Std(name, type,
intr.findWrapperName(param), intr.findWrapperName(param),
beanDesc.getClassAnnotations(), param, metadata); beanDesc.getClassAnnotations(), param, metadata);
// Is there an annotation that specifies exact deserializer?
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param);

// Type deserializer: either comes from property (and already resolved) // Type deserializer: either comes from property (and already resolved)
TypeDeserializer typeDeser = (TypeDeserializer) type.getTypeHandler(); TypeDeserializer typeDeser = (TypeDeserializer) type.getTypeHandler();
// or if not, based on type being referenced: // or if not, based on type being referenced:
Expand All @@ -856,6 +852,10 @@ protected SettableBeanProperty constructCreatorProperty(DeserializationContext c
SettableBeanProperty prop = new CreatorProperty(name, type, property.getWrapperName(), SettableBeanProperty prop = new CreatorProperty(name, type, property.getWrapperName(),
typeDeser, beanDesc.getClassAnnotations(), param, index, injectableValueId, typeDeser, beanDesc.getClassAnnotations(), param, index, injectableValueId,
metadata); metadata);
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param);
if (deser == null) {
deser = type.getValueHandler();
}
if (deser != null) { if (deser != null) {
// As per [databind#462] need to ensure we contextualize deserializer before passing it on // As per [databind#462] need to ensure we contextualize deserializer before passing it on
deser = ctxt.handlePrimaryContextualization(deser, prop, type); deser = ctxt.handlePrimaryContextualization(deser, prop, type);
Expand Down Expand Up @@ -1760,7 +1760,10 @@ protected JsonDeserializer<?> _findCustomMapLikeDeserializer(MapLikeType type,


/** /**
* Helper method called to check if a class or method * Helper method called to check if a class or method
* has annotation that tells which class to use for deserialization. * has annotation that tells which class to use for deserialization; and if
* so, to instantiate, that deserializer to use.
* Note that deserializer will NOT yet be contextualized so caller needs to
* take care to call contextualization appropriately.
* Returns null if no such annotation found. * Returns null if no such annotation found.
*/ */
protected JsonDeserializer<Object> findDeserializerFromAnnotation(DeserializationContext ctxt, protected JsonDeserializer<Object> findDeserializerFromAnnotation(DeserializationContext ctxt,
Expand Down Expand Up @@ -1806,7 +1809,7 @@ protected KeyDeserializer findKeyDeserializerFromAnnotation(DeserializationConte
* and <code>resolveType</code> * and <code>resolveType</code>
*/ */
protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt, protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt,
JavaType type, AnnotatedMember member) AnnotatedMember member, JavaType type)
throws JsonMappingException throws JsonMappingException
{ {
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
Expand All @@ -1816,8 +1819,6 @@ protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt,


// First things first: see if we can find annotations on declared // First things first: see if we can find annotations on declared
// type // type

// Also need to handle keyUsing, contentUsing


if (type.isMapLikeType()) { if (type.isMapLikeType()) {
JavaType keyType = type.getKeyType(); JavaType keyType = type.getKeyType();
Expand Down Expand Up @@ -1935,7 +1936,7 @@ protected JavaType resolveType(DeserializationContext ctxt,
BeanDescription beanDesc, JavaType type, AnnotatedMember member) BeanDescription beanDesc, JavaType type, AnnotatedMember member)
throws JsonMappingException throws JsonMappingException
{ {
return resolveMemberAndTypeAnnotations(ctxt, type, member); return resolveMemberAndTypeAnnotations(ctxt, member, type);
} }


/** /**
Expand Down
Expand Up @@ -679,6 +679,7 @@ protected void addInjectables(DeserializationContext ctxt,
* @param mutator Either 2-argument method (setter, with key and value), or Field * @param mutator Either 2-argument method (setter, with key and value), or Field
* that contains Map; either way accessor used for passing "any values" * that contains Map; either way accessor used for passing "any values"
*/ */
@SuppressWarnings("unchecked")
protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt, protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
BeanDescription beanDesc, AnnotatedMember mutator) BeanDescription beanDesc, AnnotatedMember mutator)
throws JsonMappingException throws JsonMappingException
Expand All @@ -698,18 +699,21 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
} }
// First: various annotations on type itself, as well as type-overrides // First: various annotations on type itself, as well as type-overrides
// on accessor need to be resolved // on accessor need to be resolved
type = resolveMemberAndTypeAnnotations(ctxt, type, mutator); type = resolveMemberAndTypeAnnotations(ctxt, mutator, type);
BeanProperty.Std prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
type, null, beanDesc.getClassAnnotations(), mutator,
PropertyMetadata.STD_OPTIONAL);
// and then possible direct deserializer override on accessor // and then possible direct deserializer override on accessor
JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, mutator); JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, mutator);
if (deser == null) { if (deser == null) {
deser = type.getValueHandler(); deser = type.getValueHandler();
} }
BeanProperty.Std property = new BeanProperty.Std(PropertyName.construct(mutator.getName()), if (deser != null) {
type, null, beanDesc.getClassAnnotations(), mutator, // As per [databind#462] need to ensure we contextualize deserializer before passing it on
PropertyMetadata.STD_OPTIONAL); deser = (JsonDeserializer<Object>) ctxt.handlePrimaryContextualization(deser, prop, type);
}
TypeDeserializer typeDeser = type.getTypeHandler(); TypeDeserializer typeDeser = type.getTypeHandler();
return new SettableAnyProperty(property, mutator, type, return new SettableAnyProperty(prop, mutator, type, deser, typeDeser);
deser, typeDeser);
} }


/** /**
Expand All @@ -729,9 +733,8 @@ protected SettableBeanProperty constructSettableProperty(DeserializationContext
if (ctxt.canOverrideAccessModifiers()) { if (ctxt.canOverrideAccessModifiers()) {
mutator.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); mutator.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
JavaType type = resolveMemberAndTypeAnnotations(ctxt, propType0, mutator); JavaType type = resolveMemberAndTypeAnnotations(ctxt, mutator, propType0);
// Does the Method specify the deserializer to use? If so, let's use it. // Does the Method specify the deserializer to use? If so, let's use it.
JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, mutator);
TypeDeserializer typeDeser = type.getTypeHandler(); TypeDeserializer typeDeser = type.getTypeHandler();
SettableBeanProperty prop; SettableBeanProperty prop;
if (mutator instanceof AnnotatedMethod) { if (mutator instanceof AnnotatedMethod) {
Expand All @@ -741,16 +744,21 @@ protected SettableBeanProperty constructSettableProperty(DeserializationContext
prop = new FieldProperty(propDef, type, typeDeser, prop = new FieldProperty(propDef, type, typeDeser,
beanDesc.getClassAnnotations(), (AnnotatedField) mutator); beanDesc.getClassAnnotations(), (AnnotatedField) mutator);
} }
if (propDeser != null) { JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, mutator);
prop = prop.withValueDeserializer(propDeser); if (deser == null) {
deser = type.getValueHandler();
}
if (deser != null) {
deser = ctxt.handlePrimaryContextualization(deser, prop, type);
prop = prop.withValueDeserializer(deser);
} }
// need to retain name of managed forward references: // need to retain name of managed forward references:
AnnotationIntrospector.ReferenceProperty ref = propDef.findReferenceType(); AnnotationIntrospector.ReferenceProperty ref = propDef.findReferenceType();
if (ref != null && ref.isManagedReference()) { if (ref != null && ref.isManagedReference()) {
prop.setManagedReferenceName(ref.getName()); prop.setManagedReferenceName(ref.getName());
} }
ObjectIdInfo objectIdInfo = propDef.findObjectIdInfo(); ObjectIdInfo objectIdInfo = propDef.findObjectIdInfo();
if(objectIdInfo != null){ if (objectIdInfo != null){
prop.setObjectIdInfo(objectIdInfo); prop.setObjectIdInfo(objectIdInfo);
} }
return prop; return prop;
Expand All @@ -769,15 +777,17 @@ protected SettableBeanProperty constructSetterlessProperty(DeserializationContex
if (ctxt.canOverrideAccessModifiers()) { if (ctxt.canOverrideAccessModifiers()) {
getter.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); getter.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
JavaType type = getter.getType(); JavaType type = resolveMemberAndTypeAnnotations(ctxt, getter, getter.getType());
// First: does the Method specify the deserializer to use? If so, let's use it.
JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, getter);
type = resolveMemberAndTypeAnnotations(ctxt, type, getter);
TypeDeserializer typeDeser = type.getTypeHandler(); TypeDeserializer typeDeser = type.getTypeHandler();
SettableBeanProperty prop = new SetterlessProperty(propDef, type, typeDeser, SettableBeanProperty prop = new SetterlessProperty(propDef, type, typeDeser,
beanDesc.getClassAnnotations(), getter); beanDesc.getClassAnnotations(), getter);
if (propDeser != null) { JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, getter);
prop = prop.withValueDeserializer(propDeser); if (deser == null) {
deser = type.getValueHandler();
}
if (deser != null) {
deser = ctxt.handlePrimaryContextualization(deser, prop, type);
prop = prop.withValueDeserializer(deser);
} }
return prop; return prop;
} }
Expand Down
Expand Up @@ -480,7 +480,7 @@ public abstract Object deserializeSetAndReturn(JsonParser p,
public final Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException public final Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{ {
JsonToken t = p.getCurrentToken(); JsonToken t = p.getCurrentToken();

if (t == JsonToken.VALUE_NULL) { if (t == JsonToken.VALUE_NULL) {
return _valueDeserializer.getNullValue(ctxt); return _valueDeserializer.getNullValue(ctxt);
} }
Expand Down
Expand Up @@ -33,7 +33,8 @@ public final class SetterlessProperty
protected final Method _getter; protected final Method _getter;


public SetterlessProperty(BeanPropertyDefinition propDef, JavaType type, public SetterlessProperty(BeanPropertyDefinition propDef, JavaType type,
TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedMethod method) { TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedMethod method)
{
super(propDef, type, typeDeser, contextAnnotations); super(propDef, type, typeDeser, contextAnnotations);
_annotated = method; _annotated = method;
_getter = method.getAnnotated(); _getter = method.getAnnotated();
Expand Down
Expand Up @@ -64,6 +64,7 @@ public Annotations getClassAnnotations() {
* to use for contained values (only used for properties that are * to use for contained values (only used for properties that are
* of container type) * of container type)
*/ */
@SuppressWarnings("deprecation")
protected BeanPropertyWriter buildWriter(SerializerProvider prov, protected BeanPropertyWriter buildWriter(SerializerProvider prov,
BeanPropertyDefinition propDef, JavaType declaredType, JsonSerializer<?> ser, BeanPropertyDefinition propDef, JavaType declaredType, JsonSerializer<?> ser,
TypeSerializer typeSer, TypeSerializer contentTypeSer, TypeSerializer typeSer, TypeSerializer contentTypeSer,
Expand Down Expand Up @@ -102,16 +103,6 @@ protected BeanPropertyWriter buildWriter(SerializerProvider prov,
inclusion = JsonInclude.Include.ALWAYS; inclusion = JsonInclude.Include.ALWAYS;
} }


/*
JsonInclude.Include inclusion = propDef.findInclusion().getValueInclusion();
if (inclusion == JsonInclude.Include.USE_DEFAULTS) { // since 2.6
inclusion = _defaultInclusion;
if (inclusion == null) {
inclusion = JsonInclude.Include.ALWAYS;
}
}
*/

switch (inclusion) { switch (inclusion) {
case NON_DEFAULT: case NON_DEFAULT:
// 11-Nov-2015, tatu: This is tricky because semantics differ between cases, // 11-Nov-2015, tatu: This is tricky because semantics differ between cases,
Expand Down
Expand Up @@ -46,9 +46,9 @@ public AnnotatedContextualDeserializer(String fieldName) {
} }


@Override @Override
public StringValue deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException public StringValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{ {
return new StringValue(""+_fieldName+"="+jp.getText()); return new StringValue(""+_fieldName+"="+p.getText());
} }


@Override @Override
Expand All @@ -61,38 +61,10 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
ann = property.getContextAnnotation(Name.class); ann = property.getContextAnnotation(Name.class);
} }
String propertyName = (ann == null) ? "UNKNOWN" : ann.value(); String propertyName = (ann == null) ? "UNKNOWN" : ann.value();
return new MyContextualDeserializer(propertyName); return new AnnotatedContextualDeserializer(propertyName);
} }
} }


static class MyContextualDeserializer
extends JsonDeserializer<StringValue>
implements ContextualDeserializer
{
protected final String _fieldName;

public MyContextualDeserializer() { this(""); }
public MyContextualDeserializer(String fieldName) {
_fieldName = fieldName;
}

@Override
public StringValue deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
{
return new StringValue(""+_fieldName+"="+jp.getText());
}

@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property)
throws JsonMappingException
{
String name = (property == null) ? "NULL" : property.getName();
return new MyContextualDeserializer(name);
}
}


// ensure that direct associations also work // ensure that direct associations also work
public void testAnnotatedContextual() throws Exception public void testAnnotatedContextual() throws Exception
{ {
Expand All @@ -103,5 +75,4 @@ public void testAnnotatedContextual() throws Exception
assertNotNull(bean); assertNotNull(bean);
assertEquals("xyz=a", bean.value.value); assertEquals("xyz=a", bean.value.value);
} }

} }
Expand Up @@ -175,11 +175,12 @@ public void testGenericSignature1194() throws Exception
assertEquals("Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;", t.getGenericSignature()); assertEquals("Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;", t.getGenericSignature());
} }


public void testAnchorTypeForRefTypes1206() throws Exception public void testAnchorTypeForRefTypes() throws Exception
{ {
TypeFactory tf = TypeFactory.defaultInstance(); TypeFactory tf = TypeFactory.defaultInstance();
JavaType t = tf.constructType(AtomicStringReference.class); JavaType t = tf.constructType(AtomicStringReference.class);
assertTrue(t.isReferenceType()); assertTrue(t.isReferenceType());
assertTrue(t.hasContentType());
ReferenceType rt = (ReferenceType) t; ReferenceType rt = (ReferenceType) t;
assertFalse(rt.isAnchorType()); assertFalse(rt.isAnchorType());
assertEquals(AtomicReference.class, rt.getAnchorType().getRawClass()); assertEquals(AtomicReference.class, rt.getAnchorType().getRawClass());
Expand Down

0 comments on commit feb8293

Please sign in to comment.