private synchronized AbstractConfig rebuildObjectInstance(
            final PropertyPath propertyPath,
            final Map<Class<?>, AbstractConfig> newInstanceMap) {

        final ObjectInfo<? extends AbstractConfig> objectInfo = objectInfoMap.get(propertyPath);
        if (objectInfo == null) {
            return null;
        }

        AbstractConfig instance = objectInfo.createInstance(argPropName -> {
            final PropertyPath childPropertyPath = propertyPath.merge(argPropName);
            final Prop childProp = objectInfo.getPropertyMap().get(argPropName);
            if (AbstractConfig.class.isAssignableFrom(childProp.getValueClass())) {
                // branch so recurse
                return rebuildObjectInstance(childPropertyPath, newInstanceMap);
            } else {
                // leaf
                return Optional.ofNullable(globalPropertiesMap.get(childPropertyPath))
                        .flatMap(ConfigProperty::getEffectiveValue)
                        .map(strVal ->
                                convertToObject(childProp, strVal, childProp.getValueType()))
                        .orElse(null);
            }
        });

        // Nasty hack to tweak the config to relax the security when we are in superdev mode
        instance = SuperDevUtil.relaxSecurityInSuperDevMode(instance);

        // We only want to hold the injectable instances
        // DB config objects are bound separately in AppConfigModule
        final Class<?> configClass = instance.getClass();
        if (!configClass.isAnnotationPresent(NotInjectableConfig.class)
            && !AbstractDbConfig.class.isAssignableFrom(configClass)) {
            newInstanceMap.put(configClass, instance);
        }

        return instance;
    }
This is a bit of nastiness is due to the fact that the {@link javax.xml.parsers.SAXParserFactory}
is held statically
stroom-config/stroom-config-global-impl/src/main/java/stroom/config/global/impl/ConfigMapper.java