public Result<T> validateRecursively(final T config, final Class<T> configSuperType) {
        final List<Result<T>> resultList = new ArrayList<>();

        // Validate the top level AppConfig object
        final Result<T> rootResult = validate(config, configSuperType);
        if (rootResult.hasErrorsOrWarnings()) {
            resultList.add(rootResult);
        }

        // Now validate each of the branches recursively
        // We could do this by setting @Valid on each config getter but that is liable to
        // be forgotten on new config objects
        PropertyUtil.walkObjectTree(
                config,
                prop ->
                        canValidateProp(configSuperType, prop),
                prop ->
                        validateProp(prop, resultList));

        return Result.of(resultList, configSuperType);
    }
Walks the config object tree validating each branch regardless of whether they have @Valid
annotations.
stroom-util/src/main/java/stroom/util/config/ConfigValidator.java