use of com.typesafe.config.ConfigValueType in project config by typesafehub.
the class ConfigBeanImpl method createInternal.
/**
* This is public ONLY for use by the "config" package, DO NOT USE this ABI
* may change.
* @param <T> type of the bean
* @param config config to use
* @param clazz class of the bean
* @return the bean instance
*/
public static <T> T createInternal(Config config, Class<T> clazz) {
if (((SimpleConfig) config).root().resolveStatus() != ResolveStatus.RESOLVED)
throw new ConfigException.NotResolved("need to Config#resolve() a config before using it to initialize a bean, see the API docs for Config#resolve()");
Map<String, AbstractConfigValue> configProps = new HashMap<String, AbstractConfigValue>();
Map<String, String> originalNames = new HashMap<String, String>();
for (Map.Entry<String, ConfigValue> configProp : config.root().entrySet()) {
String originalName = configProp.getKey();
String camelName = ConfigImplUtil.toCamelCase(originalName);
// the camel one wins
if (originalNames.containsKey(camelName) && !originalName.equals(camelName)) {
// if we aren't a camel name to start with, we lose.
// if we are or we are the first matching key, we win.
} else {
configProps.put(camelName, (AbstractConfigValue) configProp.getValue());
originalNames.put(camelName, originalName);
}
}
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(clazz);
} catch (IntrospectionException e) {
throw new ConfigException.BadBean("Could not get bean information for class " + clazz.getName(), e);
}
try {
List<PropertyDescriptor> beanProps = new ArrayList<PropertyDescriptor>();
for (PropertyDescriptor beanProp : beanInfo.getPropertyDescriptors()) {
if (beanProp.getReadMethod() == null || beanProp.getWriteMethod() == null) {
continue;
}
beanProps.add(beanProp);
}
// Try to throw all validation issues at once (this does not comprehensively
// find every issue, but it should find common ones).
List<ConfigException.ValidationProblem> problems = new ArrayList<ConfigException.ValidationProblem>();
for (PropertyDescriptor beanProp : beanProps) {
Method setter = beanProp.getWriteMethod();
Class<?> parameterClass = setter.getParameterTypes()[0];
ConfigValueType expectedType = getValueTypeOrNull(parameterClass);
if (expectedType != null) {
String name = originalNames.get(beanProp.getName());
if (name == null)
name = beanProp.getName();
Path path = Path.newKey(name);
AbstractConfigValue configValue = configProps.get(beanProp.getName());
if (configValue != null) {
SimpleConfig.checkValid(path, expectedType, configValue, problems);
} else {
if (!isOptionalProperty(clazz, beanProp)) {
SimpleConfig.addMissing(problems, expectedType, path, config.origin());
}
}
}
}
if (!problems.isEmpty()) {
throw new ConfigException.ValidationFailed(problems);
}
// Fill in the bean instance
T bean = clazz.newInstance();
for (PropertyDescriptor beanProp : beanProps) {
Method setter = beanProp.getWriteMethod();
Type parameterType = setter.getGenericParameterTypes()[0];
Class<?> parameterClass = setter.getParameterTypes()[0];
String configPropName = originalNames.get(beanProp.getName());
// Is the property key missing in the config?
if (configPropName == null) {
// If so, continue if the field is marked as @{link Optional}
if (isOptionalProperty(clazz, beanProp)) {
continue;
}
// Otherwise, raise a {@link Missing} exception right here
throw new ConfigException.Missing(beanProp.getName());
}
Object unwrapped = getValue(clazz, parameterType, parameterClass, config, configPropName);
setter.invoke(bean, unwrapped);
}
return bean;
} catch (InstantiationException e) {
throw new ConfigException.BadBean(clazz.getName() + " needs a public no-args constructor to be used as a bean", e);
} catch (IllegalAccessException e) {
throw new ConfigException.BadBean(clazz.getName() + " getters and setters are not accessible, they must be for use as a bean", e);
} catch (InvocationTargetException e) {
throw new ConfigException.BadBean("Calling bean method on " + clazz.getName() + " caused an exception", e);
}
}
Aggregations