Skip to content

Commit

Permalink
Fix failing tests wrt creator properties. Next: add required-ness checks
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed May 7, 2015
1 parent 6586ab3 commit b979b02
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 84 deletions.
Expand Up @@ -7,7 +7,6 @@
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;


import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty; import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator; import com.fasterxml.jackson.databind.deser.ValueInstantiator;
Expand All @@ -29,25 +28,19 @@ public final class PropertyBasedCreator
* method (whichever one is null: one property for each * method (whichever one is null: one property for each
* parameter for that one), keyed by logical property name * parameter for that one), keyed by logical property name
*/ */
protected final HashMap<String, SettableBeanProperty> _properties; protected final HashMap<String, SettableBeanProperty> _propertyLookup;


/** /**
* Number of properties: usually same as size of {@link #_properties}, * Number of properties: usually same as size of {@link #_propertyLookup},
* but not necessarily, when we have unnamed injectable properties. * but not necessarily, when we have unnamed injectable properties.
*/ */
protected final int _propertyCount; protected final int _propertyCount;

/**
* If some property values must always have a non-null value (like
* primitive types do), this array contains such default values.
*/
protected final Object[] _defaultValues;


/** /**
* Array that contains properties that expect value to inject, if any; * Array that contains properties that expect value to inject, if any;
* null if no injectable values are expected. * null if no injectable values are expected.
*/ */
protected final SettableBeanProperty[] _propertiesWithInjectables; protected final SettableBeanProperty[] _allProperties;


/* /*
/********************************************************** /**********************************************************
Expand All @@ -56,26 +49,18 @@ public final class PropertyBasedCreator
*/ */


protected PropertyBasedCreator(ValueInstantiator valueInstantiator, protected PropertyBasedCreator(ValueInstantiator valueInstantiator,
SettableBeanProperty[] creatorProps, Object[] defaultValues) SettableBeanProperty[] creatorProps)
{ {
_valueInstantiator = valueInstantiator; _valueInstantiator = valueInstantiator;
_properties = new HashMap<String, SettableBeanProperty>(); _propertyLookup = new HashMap<String, SettableBeanProperty>();
SettableBeanProperty[] propertiesWithInjectables = null;
final int len = creatorProps.length; final int len = creatorProps.length;
_propertyCount = len; _propertyCount = len;
_allProperties = new SettableBeanProperty[len];
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) {
SettableBeanProperty prop = creatorProps[i]; SettableBeanProperty prop = creatorProps[i];
_properties.put(prop.getName(), prop); _allProperties[i] = prop;
Object injectableValueId = prop.getInjectableValueId(); _propertyLookup.put(prop.getName(), prop);
if (injectableValueId != null) {
if (propertiesWithInjectables == null) {
propertiesWithInjectables = new SettableBeanProperty[len];
}
propertiesWithInjectables[i] = prop;
}
} }
_defaultValues = defaultValues;
_propertiesWithInjectables = propertiesWithInjectables;
} }


/** /**
Expand All @@ -88,23 +73,14 @@ public static PropertyBasedCreator construct(DeserializationContext ctxt,
{ {
final int len = srcProps.length; final int len = srcProps.length;
SettableBeanProperty[] creatorProps = new SettableBeanProperty[len]; SettableBeanProperty[] creatorProps = new SettableBeanProperty[len];
Object[] defaultValues = null;
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) {
SettableBeanProperty prop = srcProps[i]; SettableBeanProperty prop = srcProps[i];
if (!prop.hasValueDeserializer()) { if (!prop.hasValueDeserializer()) {
prop = prop.withValueDeserializer(ctxt.findContextualValueDeserializer(prop.getType(), prop)); prop = prop.withValueDeserializer(ctxt.findContextualValueDeserializer(prop.getType(), prop));
} }
creatorProps[i] = prop; creatorProps[i] = prop;
JsonDeserializer<?> deser = prop.getValueDeserializer(); }
Object nullValue = (deser == null) ? null : deser.getNullValue(ctxt); return new PropertyBasedCreator(valueInstantiator, creatorProps);
if (nullValue != null) {
if (defaultValues == null) {
defaultValues = new Object[len];
}
defaultValues[i] = nullValue;
}
}
return new PropertyBasedCreator(valueInstantiator, creatorProps, defaultValues);
} }


// 05-May-2015, tatu: Does not seem to be used, commented out in 2.6 // 05-May-2015, tatu: Does not seem to be used, commented out in 2.6
Expand All @@ -122,15 +98,15 @@ public void assignDeserializer(SettableBeanProperty prop, JsonDeserializer<Objec
*/ */


public Collection<SettableBeanProperty> properties() { public Collection<SettableBeanProperty> properties() {
return _properties.values(); return _propertyLookup.values();
} }


public SettableBeanProperty findCreatorProperty(String name) { public SettableBeanProperty findCreatorProperty(String name) {
return _properties.get(name); return _propertyLookup.get(name);
} }


public SettableBeanProperty findCreatorProperty(int propertyIndex) { public SettableBeanProperty findCreatorProperty(int propertyIndex) {
for (SettableBeanProperty prop : _properties.values()) { for (SettableBeanProperty prop : _propertyLookup.values()) {
if (prop.getPropertyIndex() == propertyIndex) { if (prop.getPropertyIndex() == propertyIndex) {
return prop; return prop;
} }
Expand All @@ -157,7 +133,7 @@ public PropertyValueBuffer startBuilding(JsonParser p, DeserializationContext ct
public Object build(DeserializationContext ctxt, PropertyValueBuffer buffer) throws IOException public Object build(DeserializationContext ctxt, PropertyValueBuffer buffer) throws IOException
{ {
Object bean = _valueInstantiator.createFromObjectWith(ctxt, Object bean = _valueInstantiator.createFromObjectWith(ctxt,
buffer.getParameters(_propertiesWithInjectables)); buffer.getParameters(_allProperties));
// returning null isn't quite legal, but let's let caller deal with that // returning null isn't quite legal, but let's let caller deal with that
if (bean != null) { if (bean != null) {
// Object Id to handle? // Object Id to handle?
Expand Down
Expand Up @@ -5,6 +5,8 @@


import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.SettableAnyProperty; import com.fasterxml.jackson.databind.deser.SettableAnyProperty;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty; import com.fasterxml.jackson.databind.deser.SettableBeanProperty;


Expand Down Expand Up @@ -105,65 +107,44 @@ public PropertyValueBuffer(JsonParser jp, DeserializationContext ctxt, int param
* object (usually primitive types), this is a non-null array that has such replacement * object (usually primitive types), this is a non-null array that has such replacement
* values (and nulls for cases where nulls are ok) * values (and nulls for cases where nulls are ok)
*/ */
protected final Object[] getParameters(SettableBeanProperty[] injectableProperties) protected Object[] getParameters(SettableBeanProperty[] props)
throws JsonMappingException
{ {
// quick check to see if anything else is needed // quick check to see if anything else is needed
if (_paramsNeeded > 0) { if (_paramsNeeded > 0) {
if (_paramsSeenBig == null) { if (_paramsSeenBig == null) {
_getParameters(injectableProperties); int mask = _paramsSeen;
// not optimal, could use `Integer.trailingZeroes()`, but for now should not
// really matter for common cases
for (int ix = 0, len = _creatorParameters.length; ix < len; ++ix, mask >>= 1) {
if ((mask & 1) == 0) {
_creatorParameters[ix] = _findMissing(props[ix]);
}
}
} else { } else {
_getParametersBig(injectableProperties); final int len = _creatorParameters.length;
for (int ix = 0; (ix = _paramsSeenBig.nextClearBit(ix)) < len; ++ix) {
_creatorParameters[ix] = _findMissing(props[ix]);
}
} }
} }
/*
if (prop != null) {
// null since there is no POJO yet
_creatorParameters[i] = _context.findInjectableValue(prop.getInjectableValueId(),
prop, null);
}
*/
return _creatorParameters; return _creatorParameters;
} }


private void _getParametersBig(SettableBeanProperty[] injectableProperties) protected Object _findMissing(SettableBeanProperty prop) throws JsonMappingException
{ {
final boolean hasInjectables = (injectableProperties != null); // First: do we have injectable value?
final int len = _creatorParameters.length; Object injectableValueId = prop.getInjectableValueId();
for (int ix = 0; (ix = _paramsSeenBig.nextClearBit(ix)) < len; ++ix) { if (injectableValueId != null) {
if (hasInjectables) { return _context.findInjectableValue(prop.getInjectableValueId(),
SettableBeanProperty prop = injectableProperties[ix]; prop, null);
if (prop != null) {
Object val = _context.findInjectableValue(prop.getInjectableValueId(),
prop, null);
_creatorParameters[ix] = val;
continue;
}
}
} }
// Second: required?
// Third: default value
JsonDeserializer<Object> deser = prop.getValueDeserializer();
return deser.getNullValue(_context);
} }


private void _getParameters(SettableBeanProperty[] injectableProperties)
{
final boolean hasInjectables = (injectableProperties != null);
int mask = _paramsSeen;
// not optimal, could use `Integer.trailingZeroes()`, but for now should not
// really matter for common cases
for (int ix = 0, len = _creatorParameters.length; ix < len; ++ix, mask >>= 1) {
if ((mask & 1) != 0) {
continue;
}
if (hasInjectables) {
SettableBeanProperty prop = injectableProperties[ix];
if (prop != null) {
Object val = _context.findInjectableValue(prop.getInjectableValueId(),
prop, null);
_creatorParameters[ix] = val;
continue;
}
}
}
}

/* /*
/********************************************************** /**********************************************************
/* Other methods /* Other methods
Expand Down
Expand Up @@ -93,7 +93,7 @@ public static JsonEntity create(@JsonProperty("type") String type, @JsonProperty
/* Unit tests /* Unit tests
/********************************************************** /**********************************************************
*/ */

public void testUsesDeserializersNullValue() throws Exception { public void testUsesDeserializersNullValue() throws Exception {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new TestModule()); mapper.registerModule(new TestModule());
Expand Down

0 comments on commit b979b02

Please sign in to comment.