private <T extends AbstractConfig> T mapConfigValue(final Class<T> clazz, final T value) {
        // TODO: 25/05/2023 Not sure this null check is needed
        if (NullSafe.isEmptyMap(STATIC_VALUE_MAPPERS) && NullSafe.isEmptyMap(valueMappers)) {
            // when getConfigObject is called as part of the super ctor, valueMappers will be null
            return value;
        } else if (value == null) {
            return null;
        } else {
            T newValue = value;
            boolean isMapped = false;
            final UnaryOperator<T> staticValueMapper = getStaticValueMapper(clazz);
            if (staticValueMapper != null) {
                newValue = staticValueMapper.apply(newValue);
                isMapped = true;
            }
            final UnaryOperator<T> valueMapper = getValueMapper(clazz);
            if (valueMapper != null) {
                newValue = valueMapper.apply(newValue);
                isMapped = true;
            }
            if (isMapped) {
                LOGGER.debug("Modifying value of config object {}\nbefore: {}\nafter:  {}",
                        clazz.getSimpleName(), value, newValue);
            }
            return newValue;
        }
    }
Intercepts any calls to getConfigObject and allows the returned values to be replaced
with different values for testing.
stroom-app/src/test/java/stroom/test/ConfigMapperSpy.java