private void handleDefaultsAndRequiredAndNull(DeserializationContext ctxt, ObjectNode fieldValues)
throws JsonMappingException {
Iterator<SettableBeanProperty> propertyIterator = getDelegatee().properties();
while (propertyIterator.hasNext()) {
SettableBeanProperty prop = propertyIterator.next();
String propertyName = prop.getName();
JsonNode fieldValue = fieldValues.path(propertyName);
if (fieldValue.isMissingNode() || fieldValue.isNull()) {
if (fieldDefaults.hasNonNull(propertyName)) {
fieldValue = fieldDefaults.get(propertyName).deepCopy();
fieldValues.set(propertyName, fieldValue);
} else if (prop.isRequired()) {
throw MissingPropertyException.from(ctxt.getParser(), prop.getType().getRawClass(),
propertyName, getKnownPropertyNames());
} else if (fieldValue.isNull()
&& (prop.getType().isPrimitive() || (prop.getValueDeserializer().getNullValue() == null))) {
// don't overwrite possible hard-coded defaults/ values with nulls unless they are fancy
fieldValues.remove(propertyName);
}
}
if (fieldValue.isTextual()) {
try {
// sometimes we erroneously get strings that would parse into valid numbers and maybe other edge
// cases (eg. when using system property overrides in typesafe-config). So we'll go ahead and guard
// with this regex to make sure we only get reasonable candidates.
Time time = prop.getAnnotation(Time.class);
if ((time != null) && NUMBER_UNIT.matcher(fieldValue.textValue()).matches()) {
Duration dropWizardDuration = Duration.parse(fieldValue.asText());
long asLong = time.value().convert(dropWizardDuration.getQuantity(), dropWizardDuration.getUnit());
fieldValues.put(propertyName, asLong);
} else if ((prop.getAnnotation(Bytes.class) != null) &&
NUMBER_UNIT.matcher(fieldValue.textValue()).matches()) {
Size dropWizardSize = Size.parse(fieldValue.asText());
long asLong = dropWizardSize.toBytes();
fieldValues.put(propertyName, asLong);
}
} catch (Throwable cause) {
throw JsonMappingException.wrapWithPath(cause, prop.getType().getRawClass(), propertyName);
}
}
}
}