use of com.fasterxml.jackson.databind.introspect.BasicBeanDescription in project dropwizard-guicey by xvik.
the class ConfigTreeBuilder method resolvePaths.
/**
* Use jackson serialization api to extract all configuration values with paths from configuration object.
* Always analyze types, even if actual branch is not present at all (null value) in order to always bind
* nulls and avoid "Schrodinger's binding" case. In short, bindings should not depend on configuration values
* (presence).
* <p>
* Still, bindings may vary: for example, bound implementations may differ (best example is dropwizard server type),
* as a consequences, parsed type may be different and so different properties paths could be recognized.
*
* @param config jackson serialization config
* @param content currently parsed paths
* @param type analyzed part type
* @param object analyzed part instance (may be null)
* @return all configuration paths values
*/
@SuppressWarnings({ "checkstyle:CyclomaticComplexity", "PMD.AvoidLiteralsInIfCondition" })
private static List<ConfigPath> resolvePaths(final SerializationConfig config, final ConfigPath root, final List<ConfigPath> content, final Class type, final Object object, final GenericsContext genericsContext) {
final BasicBeanDescription description = config.introspect(config.constructType(type));
for (BeanPropertyDefinition prop : description.findProperties()) {
// ignore write-only or groovy special property
if (!prop.couldSerialize() || "metaClass".equals(prop.getName())) {
continue;
}
final Object value;
// (like netflix dynamic properties) it should not break app startup
try {
value = readValue(prop.getAccessor(), object);
} catch (Exception ex) {
LOGGER.warn("Can't bind configuration path '{}' due to {}: {}. Enable debug logs to see " + "complete stack trace or use @JsonIgnore on property getter.", fullPath(root, prop), ex.getClass().getSimpleName(), ex.getMessage());
LOGGER.debug("Complete error: ", ex);
continue;
}
final ConfigPath item = createItem(root, prop, value, genericsContext);
content.add(item);
if (root != null) {
root.getChildren().add(item);
}
if (item.isCustomType() && !detectRecursion(item)) {
// build generics context for actual value type (if not null)
final GenericsContext subContext = prop.getGetter() != null ? genericsContext.method(prop.getGetter().getAnnotated()).returnTypeAs(item.getValueType()) : genericsContext.fieldTypeAs(prop.getField().getAnnotated(), item.getValueType());
resolvePaths(config, item, content, item.getValueType(), item.getValue(), subContext);
}
}
if (root != null) {
// simple properties goes up and composite objects go lower (both groups sorted alphabetically)
root.getChildren().sort(Comparator.comparing(o -> (o.isCustomType() ? 'b' : 'a') + o.getPath()));
}
return content;
}
Aggregations