Skip to content

Commit

Permalink
Fix #962
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Apr 15, 2020
1 parent 8e4de18 commit 90aa990
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 34 deletions.
4 changes: 3 additions & 1 deletion release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,12 @@ Jayson Minard (apatrida@github)
(2.8.5)
David Bakin (david-bakin@github)
* Reported #1013: `@JsonUnwrapped` is not treated as assuming `@JsonProperty("")`
* Reported #1013: `@JsonUnwrapped` is not treated as assuming `@JsonProperty("")`
(2.6.4)
* Suggested #1011: Change ObjectWriter::withAttributes() to take a Map with some kind of wildcard types
(2.7.0)
* Reported #962: `@JsonInject` fails on trying to find deserializer even if inject-only
(2.11.0)
Dmitry Romantsov (DmRomantsov@github)
* Reported #1036: Problem with case-insensitive deserialization
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project: jackson-databind

#953: i-I case conversion problem in Turkish locale with case-insensitive deserialization
(reported by Máté R)
#962: `@JsonInject` fails on trying to find deserializer even if inject-only
(reported by David B)
#1983: Polymorphic deserialization should handle case-insensitive Type Id property name
if `MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES` is enabled
(reported by soundvibe@github, fix contributed by Oleksandr P)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1013,9 +1013,8 @@ protected SettableBeanProperty constructCreatorProperty(DeserializationContext c

// Note: contextualization of typeDeser _should_ occur in constructor of CreatorProperty
// so it is not called directly here
Object injectableValueId = (injectable == null) ? null : injectable.getId();
SettableBeanProperty prop = new CreatorProperty(name, type, property.getWrapperName(),
typeDeser, beanDesc.getClassAnnotations(), param, index, injectableValueId,
SettableBeanProperty prop = CreatorProperty.construct(name, type, property.getWrapperName(),
typeDeser, beanDesc.getClassAnnotations(), param, index, injectable,
metadata);
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param);
if (deser == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.lang.annotation.Annotation;

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.databind.*;
Expand Down Expand Up @@ -40,8 +41,10 @@ public class CreatorProperty
/**
* Id of value to inject, if value injection should be used for this parameter
* (in addition to, or instead of, regular deserialization).
*
* @since 2.11
*/
protected final Object _injectableValueId;
protected final JacksonInject.Value _injectableValue;

/**
* In special cases, when implementing "updateValue", we cannot use
Expand Down Expand Up @@ -73,39 +76,72 @@ public class CreatorProperty
protected boolean _ignorable;

/**
* @since 2.11
*/
protected CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName,
TypeDeserializer typeDeser,
Annotations contextAnnotations, AnnotatedParameter param,
int index, JacksonInject.Value injectable,
PropertyMetadata metadata)
{
super(name, type, wrapperName, typeDeser, contextAnnotations, metadata);
_annotated = param;
_creatorIndex = index;
_injectableValue = injectable;
_fallbackSetter = null;
}

/**
* @deprecated Since 2.11 use factory method instead
*/
@Deprecated // since 2.11
public CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName,
TypeDeserializer typeDeser,
Annotations contextAnnotations, AnnotatedParameter param,
int index, Object injectableValueId,
PropertyMetadata metadata)
{
this(name, type, wrapperName, typeDeser, contextAnnotations, param, index,
(injectableValueId == null) ? null
: JacksonInject.Value.construct(injectableValueId, null),
metadata);
}

/**
* Factory method for creating {@link CreatorProperty} instances
*
* @param name Name of the logical property
* @param type Type of the property, used to find deserializer
* @param wrapperName Possible wrapper to use for logical property, if any
* @param typeDeser Type deserializer to use for handling polymorphic type
* information, if one is needed
* @param contextAnnotations Contextual annotations (usually by class that
* declares creator [constructor, factory method] that includes
* this property)
* @param param Representation of property, constructor or factory
* method parameter; used for accessing annotations of the property
* @param injectable Information about injectable value, if any
* @param index Index of this property within creator invocation
*
* @since 2.3
* @since 2.11
*/
public CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName,
public static CreatorProperty construct(PropertyName name, JavaType type, PropertyName wrapperName,
TypeDeserializer typeDeser,
Annotations contextAnnotations, AnnotatedParameter param,
int index, Object injectableValueId,
int index, JacksonInject.Value injectable,
PropertyMetadata metadata)
{
super(name, type, wrapperName, typeDeser, contextAnnotations, metadata);
_annotated = param;
_creatorIndex = index;
_injectableValueId = injectableValueId;
_fallbackSetter = null;
return new CreatorProperty(name, type, wrapperName, typeDeser, contextAnnotations,
param, index, injectable, metadata);
}

/**
* @since 2.3
*/
protected CreatorProperty(CreatorProperty src, PropertyName newName) {
super(src, newName);
_annotated = src._annotated;
_injectableValueId = src._injectableValueId;
_injectableValue = src._injectableValue;
_fallbackSetter = src._fallbackSetter;
_creatorIndex = src._creatorIndex;
_ignorable = src._ignorable;
Expand All @@ -115,7 +151,7 @@ protected CreatorProperty(CreatorProperty src, JsonDeserializer<?> deser,
NullValueProvider nva) {
super(src, deser, nva);
_annotated = src._annotated;
_injectableValueId = src._injectableValueId;
_injectableValue = src._injectableValue;
_fallbackSetter = src._fallbackSetter;
_creatorIndex = src._creatorIndex;
_ignorable = src._ignorable;
Expand Down Expand Up @@ -183,12 +219,12 @@ public boolean isIgnorable() {
public Object findInjectableValue(DeserializationContext context, Object beanInstance)
throws JsonMappingException
{
if (_injectableValueId == null) {
if (_injectableValue == null) {
context.reportBadDefinition(ClassUtil.classOf(beanInstance),
String.format("Property '%s' (type %s) has no injectable value id configured",
getName(), getClass().getName()));
}
return context.findInjectableValue(_injectableValueId, this, beanInstance);
return context.findInjectableValue(_injectableValue.getId(), this, beanInstance);
}

// 14-Apr-2020, tatu: Does not appear to be used so deprecated in 2.11.0,
Expand Down Expand Up @@ -220,10 +256,10 @@ public <A extends Annotation> A getAnnotation(Class<A> acls) {
@Override public int getCreatorIndex() {
return _creatorIndex;
}

/*
/**********************************************************
/* Overridden methods
/* Overridden methods, SettableBeanProperty
/**********************************************************
*/

Expand Down Expand Up @@ -274,11 +310,30 @@ public PropertyMetadata getMetadata() {
// Perhaps counter-intuitively, ONLY creator properties return non-null id
@Override
public Object getInjectableValueId() {
return _injectableValueId;
return (_injectableValue == null) ? null : _injectableValue.getId();
}

@Override
public boolean isInjectionOnly() {
return (_injectableValue != null) && !_injectableValue.willUseInput(true);
}

// public boolean isInjectionOnly() { return false; }

/*
/**********************************************************
/* Overridden methods, other
/**********************************************************
*/

@Override
public String toString() { return "[creator property, name '"+getName()+"'; inject id '"+_injectableValueId+"']"; }
public String toString() { return "[creator property, name '"+getName()+"'; inject id '"+getInjectableValueId()+"']"; }

/*
/**********************************************************
/* Internal helper methods
/**********************************************************
*/

// since 2.9
private final void _verifySetter() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,19 @@ public int getCreatorIndex() {
* value injection.
*/
public Object getInjectableValueId() { return null; }


/**
* Accessor for checking whether this property is injectable, and if so,
* ONLY injectable (will not bind from input).
* Currently (2.11) can only return {@code true} for Creator-backed properties.
*
* @return True if (and only if) property has injector that is also defined NOT
* to bind from input.
*
* @since 2.11
*/
public boolean isInjectionOnly() { return false; } // overridden by CreatorProperty

/*
/**********************************************************
/* Public API
Expand Down Expand Up @@ -730,6 +742,9 @@ public void fixAccess(DeserializationConfig config) {
@Override
public Object getInjectableValueId() { return delegate.getInjectableValueId(); }

@Override
public boolean isInjectionOnly() { return delegate.isInjectionOnly(); }

@Override
public AnnotatedMember getMember() {
return delegate.getMember();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ public static PropertyBasedCreator construct(DeserializationContext ctxt,
for (int i = 0; i < len; ++i) {
SettableBeanProperty prop = srcCreatorProps[i];
if (!prop.hasValueDeserializer()) {
prop = prop.withValueDeserializer(ctxt.findContextualValueDeserializer(prop.getType(), prop));
// 15-Apr-2020, tatu: [databind#962] Avoid getting deserializer for Inject-only
// cases
if (!prop.isInjectionOnly()) {
prop = prop.withValueDeserializer(ctxt.findContextualValueDeserializer(prop.getType(), prop));
}
}
creatorProps[i] = prop;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig confi
}

private static CreatorProperty creatorProp(String name, JavaType type, int index) {
return new CreatorProperty(PropertyName.construct(name), type, null,
return CreatorProperty.construct(PropertyName.construct(name), type, null,
null, null, null, index, null, PropertyMetadata.STD_REQUIRED);
}

@Override
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) {
return new JsonLocation(args[0], _long(args[1]), _long(args[2]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public String getValueTypeDesc() {
@Override
public CreatorProperty[] getFromObjectArguments(DeserializationConfig config) {
return new CreatorProperty[] {
new CreatorProperty(new PropertyName("type"), config.constructType(Class.class), null,
CreatorProperty.construct(new PropertyName("type"), config.constructType(Class.class), null,
null, null, null, 0, null,
PropertyMetadata.STD_REQUIRED)
};
Expand Down Expand Up @@ -147,7 +147,7 @@ public String getValueTypeDesc() {
@Override
public CreatorProperty[] getFromObjectArguments(DeserializationConfig config) {
return new CreatorProperty[] {
new CreatorProperty(new PropertyName("name"), config.constructType(String.class), null,
CreatorProperty.construct(new PropertyName("name"), config.constructType(String.class), null,
null, null, null, 0, null,
PropertyMetadata.STD_REQUIRED)
};
Expand Down Expand Up @@ -427,12 +427,12 @@ public void testPropertyBasedBeanInstantiator() throws Exception
@Override
public CreatorProperty[] getFromObjectArguments(DeserializationConfig config) {
return new CreatorProperty[] {
new CreatorProperty(new PropertyName("secret"), config.constructType(String.class), null,
CreatorProperty.construct(new PropertyName("secret"), config.constructType(String.class), null,
null, null, null, 0, null,
PropertyMetadata.STD_REQUIRED)
};
}

@Override
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) {
return new CreatorBean((String) args[0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.fasterxml.jackson.failing;
package com.fasterxml.jackson.databind.deser.inject;

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.OptBoolean;
import com.fasterxml.jackson.databind.*;

public class SkipInjectableIntrospection962Test extends BaseMapTest
// [databind#962]: "pure" Injectable that could not be deserialized
public class InjectableWithoutDeser962Test extends BaseMapTest
{
// [databind#962]
static class InjectMe
{
private String a;
Expand Down Expand Up @@ -43,8 +45,7 @@ public String getB() {
}
}

// 14-Jun-2016, tatu: For some odd reason, this test sometimes fails, other times not...
// possibly related to unstable ordering of properties?
// [databind#962]
public void testInjected() throws Exception
{
InjectMe im = new InjectMe(true);
Expand Down

0 comments on commit 90aa990

Please sign in to comment.