diff --git a/release-notes/VERSION b/release-notes/VERSION index 72ed7b3192..fdb0c5c289 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -49,6 +49,8 @@ Project: jackson-databind configurable/external equality comparison #794: Add `SerializationFeature.WRITE_DATES_WITH_ZONE_ID` to allow inclusion/exclusion of timezone id for date/time values (as opposed to timezone offset) +#795: Converter annotation not honored for abstract types + (reported by myrosia@github) - Remove old cglib compatibility tests; cause problems in Eclipse 2.5.4 (not yet released) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index 1ade8b9131..aec0b5f964 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -411,7 +411,6 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config // may need to keep track for [#725] List implicitCtors = null; - for (AnnotatedConstructor ctor : beanDesc.getConstructors()) { final boolean isCreator = intr.hasCreatorAnnotation(ctor); BeanPropertyDefinition[] propDefs = creatorParams.get(ctor); @@ -446,7 +445,7 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config // 2 or more args; all params must have names or be injectable // 14-Mar-2015, tatu (2.6): Or, as per [#725], implicit names will also // do, with some constraints. But that will require bit post processing... - + AnnotatedParameter nonAnnotatedParam = null; CreatorProperty[] properties = new CreatorProperty[argCount]; int explicitNameCount = 0; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index 28b676f8c3..32a49f942f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -20,8 +20,8 @@ public class BeanDeserializer { /* TODOs for future versions: * - * For 2.6? - * + * For 2.7? + * * - New method in JsonDeserializer (deserializeNext()) to allow use of more * efficient 'nextXxx()' method `JsonParser` provides. * @@ -429,7 +429,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri unknown.writeFieldName(propName); unknown.copyCurrentStructure(p); } - + // We hit END_OBJECT, so: Object bean; try { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java index 8e8c48fa5a..c6aa9858bc 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java @@ -407,11 +407,11 @@ public void resolve(DeserializationContext ctxt) { ExternalTypeHandler.Builder extTypes = null; // if ValueInstantiator can use "creator" approach, need to resolve it here... + SettableBeanProperty[] creatorProps; if (_valueInstantiator.canCreateFromObjectWith()) { - SettableBeanProperty[] creatorProps = _valueInstantiator.getFromObjectArguments(ctxt.getConfig()); - _propertyBasedCreator = PropertyBasedCreator.construct(ctxt, _valueInstantiator, creatorProps); + creatorProps = _valueInstantiator.getFromObjectArguments(ctxt.getConfig()); // also: need to try to resolve 'external' type ids... - for (SettableBeanProperty prop : _propertyBasedCreator.properties()) { + for (SettableBeanProperty prop : creatorProps) { if (prop.hasValueTypeDeserializer()) { TypeDeserializer typeDeser = prop.getValueTypeDeserializer(); if (typeDeser.getTypeInclusion() == JsonTypeInfo.As.EXTERNAL_PROPERTY) { @@ -422,12 +422,15 @@ public void resolve(DeserializationContext ctxt) } } } + } else { + creatorProps = null; } UnwrappedPropertyHandler unwrapped = null; for (SettableBeanProperty origProp : _beanProperties) { SettableBeanProperty prop = origProp; + // May already have deserializer from annotations, if so, skip: if (!prop.hasValueDeserializer()) { // [Issue#125]: allow use of converters @@ -447,6 +450,7 @@ public void resolve(DeserializationContext ctxt) prop = prop.withValueDeserializer(cd); } } + // [JACKSON-235]: need to link managed references with matching back references prop = _resolveManagedReferenceProperty(ctxt, prop); @@ -472,11 +476,29 @@ public void resolve(DeserializationContext ctxt) prop = _resolveInnerClassValuedProperty(ctxt, prop); if (prop != origProp) { _beanProperties.replace(prop); + // [databind#795]: Make sure PropertyBasedCreator's properties stay in sync + if (creatorProps != null) { + // 18-May-2015, tatu: _Should_ start with consistent set. But can we really + // fully count on this? May need to revisit in future; seems to hold for now. + for (int i = 0, len = creatorProps.length; i < len; ++i) { + if (creatorProps[i] == origProp) { + creatorProps[i] = prop; + break; + } + // ... as per above, it is possible we'd need to add this as fallback + // if (but only if) identity check fails? + /* + if (creatorProps[i].getName().equals(prop.getName())) { + creatorProps[i] = prop; + break; + } + */ + } + } } - /* one more thing: if this property uses "external property" type inclusion - * (see [JACKSON-453]), it needs different handling altogether - */ + // one more thing: if this property uses "external property" type inclusion + // (see [JACKSON-453]), it needs different handling altogether if (prop.hasValueTypeDeserializer()) { TypeDeserializer typeDeser = prop.getValueTypeDeserializer(); if (typeDeser.getTypeInclusion() == JsonTypeInfo.As.EXTERNAL_PROPERTY) { @@ -522,7 +544,12 @@ public void resolve(DeserializationContext ctxt) } _delegateDeserializer = dd; } - + + // And now that we know CreatorProperty instances are also resolved can finally create the creator: + if (creatorProps != null) { + _propertyBasedCreator = PropertyBasedCreator.construct(ctxt, _valueInstantiator, creatorProps); + } + if (extTypes != null) { _externalTypeIdHandler = extTypes.build(); // we consider this non-standard, to offline handling diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java index 89914835a1..ce73b6d9fa 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java @@ -534,13 +534,13 @@ protected void addBeanProps(DeserializationContext ctxt, +name+"' (in class "+beanDesc.getBeanClass().getName()+")"); } if (prop != null) { - cprop = cprop.withFallbackSetter(prop); + cprop.setFallbackSetter(prop); } prop = cprop; builder.addCreatorProperty(cprop); continue; } - + if (prop != null) { Class[] views = propDef.findViews(); if (views == null) { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java b/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java index 7151878090..6a9ee45f7b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/CreatorProperty.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.introspect.AnnotatedMember; import com.fasterxml.jackson.databind.introspect.AnnotatedParameter; @@ -50,11 +49,14 @@ public class CreatorProperty * In special cases, when implementing "updateValue", we can not use * constructors or factory methods, but have to fall back on using a * setter (or mutable field property). If so, this refers to that fallback - * accessor + * accessor. + *

+ * Mutable only to allow setting after construction, but must be strictly + * set before any use. * * @since 2.3 */ - protected final SettableBeanProperty _fallbackSetter; + protected SettableBeanProperty _fallbackSetter; /** * @param name Name of the logical property @@ -102,17 +104,6 @@ protected CreatorProperty(CreatorProperty src, JsonDeserializer deser) { _fallbackSetter = src._fallbackSetter; } - /** - * @since 2.3 - */ - protected CreatorProperty(CreatorProperty src, SettableBeanProperty fallbackSetter) { - super(src); - _annotated = src._annotated; - _creatorIndex = src._creatorIndex; - _injectableValueId = src._injectableValueId; - _fallbackSetter = fallbackSetter; - } - @Override public CreatorProperty withName(PropertyName newName) { return new CreatorProperty(this, newName); @@ -123,10 +114,16 @@ public CreatorProperty withValueDeserializer(JsonDeserializer deser) { return new CreatorProperty(this, deser); } - public CreatorProperty withFallbackSetter(SettableBeanProperty fallbackSetter) { - return new CreatorProperty(this, fallbackSetter); + /** + * NOTE: one exception to immutability, due to problems with CreatorProperty instances + * being shared between Bean, separate PropertyBasedCreator + * + * @since 2.6.0 + */ + public void setFallbackSetter(SettableBeanProperty fallbackSetter) { + _fallbackSetter = fallbackSetter; } - + /** * Method that can be called to locate value to be injected for this * property, if it is configured for this. diff --git a/src/test/java/com/fasterxml/jackson/failing/ConvertingAbstractSerializer795Test.java b/src/test/java/com/fasterxml/jackson/databind/convert/ConvertingAbstractSerializer795Test.java similarity index 98% rename from src/test/java/com/fasterxml/jackson/failing/ConvertingAbstractSerializer795Test.java rename to src/test/java/com/fasterxml/jackson/databind/convert/ConvertingAbstractSerializer795Test.java index d3d3b43182..3fceada612 100644 --- a/src/test/java/com/fasterxml/jackson/failing/ConvertingAbstractSerializer795Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/convert/ConvertingAbstractSerializer795Test.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.convert; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.*; @@ -47,7 +47,6 @@ public NonAbstractCustomType(String v) { } } - public static class NonAbstractCustomTypeDeserializationConverter extends StdConverter{ @Override @@ -56,7 +55,6 @@ public NonAbstractCustomType convert(String arg) { } } - public static class NonAbstractCustomTypeUser { @JsonProperty @JsonDeserialize(converter = NonAbstractCustomTypeDeserializationConverter.class)