static <T> T mergeInStroomDefaults(final String prefix,
                                       final T vanillaConfig,
                                       final T stroomDefaultConfig,
                                       final T actualConfig) {
        if (stroomDefaultConfig != null) {
            final Map<String, Prop> props = PropertyUtil.getProperties(vanillaConfig);

            props.forEach((propName, prop) -> {
                // Value from the dropwiz class as is
                final Object vanillaValue = getPropValue(prop, vanillaConfig);
                // Our hard coded sensible default (may be same as above)
                final Object stroomDefaultValue = getPropValue(prop, stroomDefaultConfig);
                // Value from yaml
                Object actualValue = getPropValue(prop, actualConfig);
                LOGGER.debug("Prop: {}.{}\nVanilla: {}\nStroom Default: {}\nActual: {}",
                        prefix, propName, vanillaValue, stroomDefaultValue, actualValue);

                if (propName.equals(TLS_PROP_NAME)
                    && (stroomDefaultValue != null || actualValue != null)) {
                    if (vanillaValue != null) {
                        throw new RuntimeException("Expecting vanilla config to be null. " +
                                                   "Have DropWizard changed their default config");
                    }
                    final Object mergedValue;
                    if (stroomDefaultValue != null && actualValue == null) {
                        mergedValue = stroomDefaultValue;
                    } else {
                        // tls config is null in vanilla config
                        mergedValue = mergeInStroomDefaults(
                                TLS_PROP_NAME,
                                new TlsConfiguration(),
                                stroomDefaultValue,
                                actualValue);
                    }
                    prop.setValueOnConfigObject(actualConfig, mergedValue);
                } else if (propName.equals(PROXY_PROP_NAME)
                           && (stroomDefaultValue != null || actualValue != null)) {
                    if (vanillaValue != null) {
                        throw new RuntimeException("Expecting vanilla config to be null. " +
                                                   "Have DropWizard changed their default config");
                    }
                    final Object mergedValue;
                    if (stroomDefaultValue != null && actualValue == null) {
                        mergedValue = stroomDefaultValue;
                    } else {
                        // proxy (as in a proxy server, not stroom-proxy) config is null in vanilla config
                        mergedValue = mergeInStroomDefaults(PROXY_PROP_NAME,
                                new ProxyConfiguration(),
                                stroomDefaultValue,
                                actualValue);
                    }
                    prop.setValueOnConfigObject(actualConfig, mergedValue);
                } else {
                    if (Objects.equals(vanillaValue, actualValue)
                        && !Objects.equals(vanillaValue, stroomDefaultValue)) {
                        // yaml value is same as DW default but stroom has a different default
                        // so apply that
                        LOGGER.debug(() ->
                                LogUtil.message("Changing property {} from {} to stroom default {}",
                                        prefix + propName, vanillaValue, stroomDefaultValue));
                        prop.setValueOnConfigObject(actualConfig, stroomDefaultValue);
                    }
                }
            });
        }
        return actualConfig;
    }
@return The prefix for the user agent name
stroom-dropwizard-common/src/main/java/stroom/dropwizard/common/AbstractJerseyClientFactory.java