SerializedConfigValue(Config conf) { this(conf.root()); this.wasConfig = true; }
/** * 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); // if a setting is in there both as some hyphen name and the camel name, // 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 { 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]; Object unwrapped = getValue( clazz, parameterType, parameterClass, config, originalNames.get(beanProp.getName())); 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); } }